【问题标题】:Problems making radial gradient in arcs using javascript, d3 with data from json file使用 javascript、d3 和 json 文件中的数据在弧中制作径向渐变的问题
【发布时间】:2021-03-01 08:40:47
【问题描述】:

我正在使用 javascript 和 d3 (v6) 并努力制作 sunburst type plot 或者至少有一个带有arcs at different radial distances 的图,其中每个弧都可能有自己的梯度(从中心到外围的径向梯度)。在这一点上,我遵循了一些示例(例如herehere),在这些示例中我设置了一组radialGradient 元素,然后使用其中的 id 在我的实际弧中生成填充。但是我正在从 json 文件中的数据生成我的弧线和渐变,这使得它与以前的问题不同,因为 svg 元素生成在 d3.json 调用中(例如here)。我有两个问题。 (1) 渐变设置有如下线条:

grads.append("stop")
        .attr("offset", "0%").style("stop-color", "white")
        .attr("offset", "100%").style("stop-color", "green");

但这些似乎并没有真正添加到 grads 元素中(当我查看网页中的检查器时)。
(2) 弧的链接似乎不起作用,尽管这可能是因为第一个问题。

JAVASCRIPT(可以找到here

var width = window.innerWidth,
    height = window.innerHeight;

var body = d3.select('body')

// append svg to the DIV
chart = d3.select(".chart");

const svg = chart.append("svg:svg")
    .attr("width", width)
    .attr("height", height);

///////////////////////////////////////  Global variables controlling the arc appearance //////////////////
const arcMin = 30;
const arcWidth = 45.5;
const arcPad = 1;
///////////////////////////////////////////////////////////////////////////////////////////////

d3.json('dataExample.json')
    .then(function (data) {

        const grads = svg.append("defs").selectAll("radialGradient").data(data.sequences);
        grads.enter().append("radialGradient")
            .attr("gradientUnits", "objectBoundingBox")
            .attr("cx", 0)
            .attr("cy", 0)
            .attr("fr", (d, i) => arcMin + (d.pulse-1) * (arcWidth))
            .attr("r", (d, i) => arcMin + d.pulse * (arcWidth))
            .attr("id", function (d) {
                return "grad" + d.code;
            });
        grads.append("stop")
            .attr("offset", "0%").style("stop-color", "white")
            .attr("offset", "100%").style("stop-color", "green");//eventually this gradient will go between two colors that are functions of the data that is read in from the json file

        console.log(grads);

        var arc = svg.selectAll('path.arc-path')
            .data(data.sequences);
        arc.enter()
            .append('svg:path')
            .attr('d', d3.arc()
                .innerRadius((d, i) => arcMin + (d.pulse - 1) * (arcWidth) + arcPad)
                .outerRadius((d, i) => arcMin + d.pulse * (arcWidth))
                .startAngle(function (d, i) {
                    ang = (i * 30) * Math.PI / 180;
                    return ang;
                })
                .endAngle(function (d, i) {
                    ang = ((i + 1) * 30) * Math.PI / 180;
                    return ang;
                })
            )
            .attr("class", ".arc-path") // assigns a class for easier selecting
            .attr("transform", "translate(600,300)") 
            //.style('fill',(d) => `rgb(${d.code * 10},${d.code*20},${255 -d.code * 7})`); this works - but doesn't use the gradients
            .style("fill", function (d) {return "url(#grad" + d.code + ")";})


    })

JSONFILE(上面称为dataExample.json)可以找到here

{"type":"sequenceData","sequences":[{"pulse":1,"code":0},{"pulse":1,"code":1},{"pulse":1,"code":2},{"pulse":2,"code":3},{"pulse":2,"code":4},{"pulse":2,"code":5},{"pulse":2,"code":6},{"pulse":2,"code":7},{"pulse":2,"code":8},{"pulse":2,"code":9},{"pulse":2,"code":10},{"pulse":3,"code":12}]}

index.html(可以找到here

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Gradient arc test</title>
    </style>
    <script type="text/javascript" src="https://d3js.org/d3.v6.min.js"></script>
  </head>
  <body>
    <div class="chart"></div>
        <script src="arcExample.js">    </script>
  </body>
</html>

如果您发现其他问题或错误的编码习惯,请告诉我,因为我是新手。 谢谢。

(已编辑)

根据 Ruben Helsloot 的评论,我对各个部分做了一些 jsfiddles。有4个小提琴。它们在两个方面有所不同:(1)如何读取 json 文件和(2)如何生成填充。我会注意到,出于我的最终目的,我需要能够从文件中读取 json 文件 - 无论是本地文件还是 URL
(1) jsfiddle Version 1 尝试从 URL 读取 json 并尝试使用渐变进行填充。我认为从 url 读取有问题,渐变填充也有问题。
(2) jsfiddle Version 2 尝试从 URL 读取 json,但不使用渐变填充。这在读取 URL 时存在问题。当我在本地机器上从本地文件读取 json 时执行此操作时,此版本会生成输出(尽管不是渐变)。
(3) jsfiddle Version 3 这会将 json 放入一个名为 data 的局部变量中,然后使用它。它还尝试使用渐变进行填充。
(4) jsfiddle Version 4 这会将 json 放入一个名为 data 的局部变量中,然后使用它。它不使用渐变填充。这是 4 个在 jsfiddle 上提供输出的唯一一个。

【问题讨论】:

  • 请将您的代码转换为可运行的minimal reproducible example,它将帮助我们了解发生了什么。您可以在 github 上托管您的 JSON 文件,或者将其存储为变量 data 并删除 d3.json 调用
  • 我编辑了帖子,其中包含指向 4 个 jsfiddles 的链接,其中包含显示问题的变体。使用 d3.json 从 URL 读取时出现问题。最终,我需要能够从文件或 URL 中读取数据,而不是将数据保存在 javascript 文件本身中。我还在 gitlab(问题中的链接)上发布了 index.html、arcExample.js 和 dataExample.json 文件以进行本地测试。

标签: json svg d3.js radial-gradients sunburst-diagram


【解决方案1】:

您应该先学习基本的 SVG 1.1 规范,然后再学习如何将元素(而非属性)添加到正确的 SVG 结构中。

以下是固定代码,虽然我不知道你想要实现什么渐变。您可以尝试将 gradientUnits 属性改回 objectBoundingBox,但首先也要尝试使用 r 属性。

var width = window.innerWidth,
    height = window.innerHeight;

var body = d3.select('body')

// append svg to the DIV
chart = d3.select(".chart");

const svg = chart.append("svg:svg")
    .attr("width", width)
    .attr("height", height)
    .attr("xmlns", "http://www.w3.org/2000/svg")
    .attr("xmlns:xlink", "http://www.w3.org/1999/xlink");

///////////////////////////////////////  Global variables controlling the arc appearance //////////////////
const arcMin = 30;
const arcWidth = 45.5;
const arcPad = 1;
///////////////////////////////////////////////////////////////////////////////////////////////

var data = {"type":"sequenceData","sequences":[{"pulse":1,"code":0},{"pulse":1,"code":1},{"pulse":1,"code":2},{"pulse":2,"code":3},{"pulse":2,"code":4},{"pulse":2,"code":5},{"pulse":2,"code":6},{"pulse":2,"code":7},{"pulse":2,"code":8},{"pulse":2,"code":9},{"pulse":2,"code":10},{"pulse":3,"code":12}]};

        const grads = svg.append("defs").selectAll("radialGradient").data(data.sequences);
        gradsWrap = grads.enter().append("radialGradient")
            //.attr("gradientUnits", "objectBoundingBox")
            .attr("gradientUnits", "userSpaceOnUse")
            .attr("cx", 0)
            .attr("cy", 0)
            //.attr("fr", (d, i) => arcMin + (d.pulse-1) * (arcWidth))
            //.attr("r", (d, i) => arcMin + (d.pulse-1) * (arcWidth))
            .attr("fr", "0%")
            .attr("r", "25%")
            .attr("id", function (d) {
                return "grad" + d.code;
            })
        gradsWrap.append("stop")
            .attr("offset", "0%")
            .attr("stop-color", "white");
        gradsWrap.append("stop")
            .attr("offset", "100%").attr("stop-color", "green");//eventually this gradient will go between two colors that are functions of the data that is read in from the json file

        console.log(grads);

        var arc = svg.selectAll('path.arc-path')
            .data(data.sequences);
        arc.enter()
            .append('svg:path')
            .attr('d', d3.arc()
                .innerRadius((d, i) => arcMin + (d.pulse - 1) * (arcWidth) + arcPad)
                .outerRadius((d, i) => arcMin + d.pulse * (arcWidth))
                .startAngle(function (d, i) {
                    ang = (i * 30) * Math.PI / 180;
                    return ang;
                })
                .endAngle(function (d, i) {
                    ang = ((i + 1) * 30) * Math.PI / 180;
                    return ang;
                })
            )
            .attr("class", ".arc-path") // assigns a class for easier selecting
            .attr("transform", "translate(" + width/2 + "," + height/2 + ")")
            .attr('stroke', 'white')
            .style('stroke-width', '2px')
            .attr("fill", function (d) {
              //return "red";
              return "url(#grad" + d.code + ")";
            })
<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  <title>Gradient arc test</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
</head>

<body>
  <div class="chart"></div>
</body>

【讨论】:

  • 基于您的代码和我的代码基于here 的示例,我还尝试删除const grads = svg.append("defs").selectAll("radialGradient").data(data.sequences) 之后的分号并直接进入.enter().append("radialGradient")... 部分,而不是添加额外的 gradsWrap 变量它也很有效。这说明了很多。
  • 当然,您只需要区分是向一个 SVG 元素添加属性还是子元素。在后一种情况下,通常需要多个子元素,定义“包装”(变量)元素的方法是实用的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 2021-08-06
相关资源
最近更新 更多