首页 > 解决方案 > 使用 javascript、d3 和来自 json 文件的数据在弧中制作径向渐变的问题

问题描述

我正在使用 javascript 和 d3 (v6) 并致力于制作一个旭日形图 或至少一个具有不同径向距离的弧的图,其中每个弧可能有自己的梯度(从中心到外围的径向梯度)。在这一点上,我已经遵循了一些示例(例如, herehere),其中我设置了一组radialGradient 元素,然后使用其中的 id 来生成我的实际弧线中的填充。但是我正在从 json 文件中的数据生成我的弧线和渐变,这使得它与以前的问题不同,因为 svg 元素生成在 d3.json 调用中(例如这里)。我有两个问题。(1) 渐变设置的线条如下:

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

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

JAVASCRIPT(可以在这里找到)

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)可以在这里找到

{"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(可以在这里找到)

<!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 版本 1尝试从 URL 读取 json 并尝试使用渐变进行填充. 我认为从 url 读取有问题,渐变填充也有问题。
(2) jsfiddle 版本 2尝试从 URL 读取 json,但不使用渐变填充。这在读取 URL 时存在问题。当我在本地机器上从本地文件中读取 json 时,这个版本会生成输出(尽管不是渐变)。
(3) jsfiddle 版本 3这会将 json 放入一个名为 data 的局部变量中,然后使用它。它还尝试使用渐变进行填充。
(4) jsfiddle 版本 4这将 json 放入一个名为 data 的局部变量中,然后使用它。它不使用渐变填充。这是 4 个在 jsfiddle 上提供输出的唯一一个。

标签: jsonsvgd3.jsradial-gradientssunburst-diagram

解决方案


您应该先学习基本的 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>


推荐阅读