简体   繁体   English

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

[英]how to create three-level donut chart in d3.js

这是三级甜甜圈图的图像

I'm using trying to create a multi-level donut chart in d3 version5 This image is drawn by d3 version3.我正在尝试在 d3 version5 中创建多级圆环图 此图像由 d3 version3 绘制。 it is working fine in version3.它在 version3 中工作正常。 I decided to upgrade d3 to the latest version.我决定将 d3 升级到最新版本。 now, donut chart is not drawn by d3(also no errors in the console)现在,d3 没有绘制甜甜圈图(控制台中也没有错误)

D3 version 3 > version 5 D3 版本 3 > 版本 5


Here is the sample dataset I used:这是我使用的示例数据集:

Hint: first value in the array is used storage and second is free storage提示:数组中的第一个值是已用存储第二个空闲存储

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

Note: Above data is just a sample this is not exact data.注:以上数据仅为样本,并非准确数据。

Here is the code I tried:这是我试过的代码

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);
});

Note: This code is working fine in d3 version3 .注意:此代码在d3 version3 中工作正常。

2. Update : 2. 更新

I've updated the answer with a better solution.我已经用更好的解决方案更新了答案。 I didn't do this at first, because I didn't grasp you structure.一开始我没有这样做,因为我没有掌握你的结构。 I've updated it to being more D3 idiomatic.我已将其更新为更符合 D3 惯用语。 Plus it does away with the hack I made in my first update :)此外,它消除了我在第一次更新中所做的 hack :)

    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);
        })
    })

The updated code uses the index (here j ) that is available when appending the g elements, which corresponds to you original j index.更新后的代码使用附加g元素时可用的索引(此处为j ),该索引对应于原始j索引。 This makes it possible to calculate the radii in the original way.这使得以原始方式计算半径成为可能。 To achieve this, the arc appending code is wrapped into a .each function that iterates over the g elements, making j available to us.为了实现这一点,弧附加代码被包装到一个.each函数中,该函数迭代g元素,使我们可以使用j

The class application should work as well, but I've commented it out, as the classFn function doesn't work, since the classes variable is not present.类应用程序也应该可以工作,但我已经将其注释掉了,因为classFn函数不起作用,因为classes变量不存在。

1. Update : 1. 更新

Besides the original answer, when calculating the arc radii you rely on a j value that is different from D3 v3 and v5.除了原始答案,在计算弧半径时,您依赖于不同于 D3 v3 和 v5 的j值。 I summise that j is used the index of the d3.values array, so I've cooked up a way to reverse look-up that index based on the input values.我总结出j被用作d3.values数组的索引,所以我想出了一种基于输入值反向查找该索引的方法。

First create a map for reverse mapping data values into their corresponding index:首先创建一个映射,用于将数据值反向映射到它们对应的索引中:

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
}, {})

Then change the last part of your code to:然后将代码的最后一部分更改为:

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);
});

It might not be too pretty, but it's a simple adaption of your code that works.它可能不太漂亮,但它是对您的代码的简单改编。

------- Original answer -------- -------原答案--------

In D3 v5 pie and arc are found at d3.pie and d3.arc respectively.在 D3 v5 pie 和 arc 分别位于d3.pied3.arc Therefore, try changing:因此,尝试更改:

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

To this instead:对此:

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

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

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

If you use a bundler to bundle sub-modules, both are part of the d3-shape module.如果您使用捆绑器来捆绑子模块,则它们都是d3-shape模块的一部分。 If not they are both available in the full D3 library.如果没有,它们都在完整的 D3 库中可用。

Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM