如何在d3.js中创建三级甜甜圈图

时间:2019-08-13 06:56:09

标签: javascript d3.js

here is the image for three-level donut chart

我正在尝试在D3版本5中创建多级甜甜圈图 此图像由d3版本3绘制。在version3中工作正常。我决定将d3升级到最新版本。现在,d3不会绘制甜甜圈图(控制台中也没有错误)

D3版本3>版本5


这是我使用的示例数据集:

提示::数组中的第一个值已用存储空间第二个免费存储空间< / strong>

 {
    average: [30.012, 69.988],
    minimum: [10, 90],
    maximum: [40, 60]
}

注意:以上数据仅是示例,并非精确数据。

这是我尝试的代码

var width = 300;
var height = 300;
var radius = Math.floor((width / 6) - 2);

var classFn = function(a, b) {
    return a === 0 ? classes[b] : 'default';
};

var pie = d3.layout.pie().sort(null);
var arc = d3.svg.arc();

var svg = d3.select(selector).append("svg");
svg.attr("width", width);
svg.attr("height", height);
svg = svg.append("g");
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");
var path = gs.selectAll("path");
path = path.data(function(d) {
    return pie(d);
});
path.enter().append("path");
path.attr("class", function(d, i, j) {
    return classFn(i, j);
})
path.attr("d", function(d, i, j) {
    return arc.innerRadius((j === 0 ? 0 : 2) + radius * j).outerRadius(radius * (j + 1))(d);
});

注意:该代码在 d3版本3 中正常工作。

1 个答案:

答案 0 :(得分:0)

2。更新

我已经用更好的解决方案更新了答案。起初我没有这样做,因为我不了解您的结构。我已将其更新为更加D3惯用的方式。另外,它还消除了我在第一次更新中所做的破解:)

    var dataset = {
      average: [0, 100],
      minimum: [0, 100],
      maximum: [0, 100]
    }

    var width = 300;
    var height = 300;
    var radius = Math.floor((width / 6) - 2);

    var pie = d3.pie().sort(null);
    var arc = d3.arc();

    var svg = d3.select('body').append("svg");
    svg.attr("width", width);
    svg.attr("height", height);
    svg = svg.append("g");
    svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    var gs = svg.selectAll("g").data(d3.values(dataset)).enter().append("g");

    gs.each(function (d, j) {
      d3.select(this).selectAll('path')
        .data(pie(d)).enter()
        .append('path')
        .attr("class", function(d, i) {
          // return classFn(i);
        })
        .attr('d', function (d) {
          return arc
            .innerRadius((j === 0 ? 0 : 2) + radius * j)
            .outerRadius(radius * (j + 1))(d);
        })
    })

更新的代码使用在附加j元素时可用的索引(此处为g),该元素对应于您原始的j索引。这样就可以以原始方式计算半径。 为此,将弧附加代码包装到.each元素中的g函数中,使j对我们可用。

类应用程序也应该可以正常工作,但由于classFn函数不存在,因此classes函数不起作用,因此我已经注释掉了。

1。更新

除原始答案外,在计算弧半径时,您还依赖于j值,该值不同于D3 v3和v5。我总结一下,j被用作d3.values数组的索引,因此我已经找到了一种基于输入值来反向查找该索引的方法。

首先创建一个映射,用于将数据值反向映射到其对应的索引中:

var dataValueJoinChar = '¤'
var datasetValuesToIndex = d3.values(dataset).reduce((acc, curr, i) => {
  acc[`0${dataValueJoinChar}${curr[0]}`] = i
  acc[`1${dataValueJoinChar}${curr[1]}`] = i
  return acc
}, {})

然后将代码的最后一部分更改为:

path = path.data(function(d) {
  return pie(d);
}).enter().append("path");

path.attr("class", function(d, i, j) {
  return classFn(i, j);
})

path.attr("d", function(d, i, j) {
  var orgIndex = datasetValuesToIndex[`${i}${dataValueJoinChar}${d.data}`]
  return arc
    .innerRadius((orgIndex === 0 ? 0 : 2) + radius * orgIndex)
    .outerRadius(radius * (orgIndex + 1))(d);
});

它可能不太漂亮,但这只是对您的代码进行了简单的改编即可。

------- 原始答案 --------

在D3 v5中,分别在d3.pied3.arc处找到饼图和圆弧。因此,请尝试更改:

var pie = d3.layout.pie().sort(null);
var arc = d3.svg.arc();

为此:

var pie = d3.pie().sort(null);
var arc = d3.arc();

Pie API参考:https://github.com/d3/d3-shape/blob/v1.3.4/README.md#pie

Arc API参考:https://github.com/d3/d3-shape/blob/v1.3.4/README.md#arc

如果使用捆绑器捆绑子模块,则两者都是d3-shape模块的一部分。如果没有,则它们都可以在完整的D3库中使用。

希望这会有所帮助!