简体   繁体   中英

d3.js Multi level pie chart with per-slice offset start angles

I have a pie chart here https://codepen.io/dbousamra/pen/rNVyMNR

I am trying to build this:

图表

Notice the angles and offsets of the 2nd slices in the Pie? How do I achieve this?

var width = 600,
    height = 450,
    maxRadius = Math.min(width, height) / 2;

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


var multiLevelData = [];
var setMultiLevelData = function(data) {
    if (data == null)
        return;
    var level = data.length,
        counter = 0,
        index = 0,
        currentLevelData = [],
        queue = [];
    for (var i = 0; i < data.length; i++) {
        queue.push(data[i]);
    };

    while (!queue.length == 0) {
        var node = queue.shift();
        currentLevelData.push(node);
        level--;

        if (node.subData) {
            for (var i = 0; i < node.subData.length; i++) {
                queue.push(node.subData[i]);
                counter++;
            };
        }
        if (level == 0) {
            level = counter;
            counter = 0;            multiLevelData.push(currentLevelData);
            currentLevelData = [];
        }
    }
}

var drawPieChart = function(_data, index) {
    var pie = d3.layout.pie()
        .sort(null)
        .value(function(d) {
            return d.nodeData.size;
        });
    var arc = d3.svg.arc()
        .outerRadius((index + 1) * pieWidth - 1)
        .innerRadius(index * pieWidth)
        .startAngle((d) => d.startAngle + Math.PI/4 )
        .endAngle((d) => d.endAngle + Math.PI/4 );

    var g = svg.selectAll(".arc" + index).data(pie(_data)).enter().append("g")
        .attr("class", "arc" + index);

    g.append("path").attr("d", arc)
        .style("fill", function(d) {
            return color(d.data.nodeData.number);
        });

    g.append("text").attr("transform", function(d) {
            return "translate(" + arc.centroid(d) + ")";
        })
        .attr("dy", ".35em").style("text-anchor", "middle")
        .text(function(d) {
            return d.data.nodeData.number;
        });
}


setMultiLevelData(data);

var pieWidth = parseInt(maxRadius / multiLevelData.length) - multiLevelData.length;

var color = d3.scale.category20();

for (var i = 0; i < multiLevelData.length; i++) {
    var _cData = multiLevelData[i];
    drawPieChart(_cData, i);
}

And the data:

<script>
  /*
  Here is the compact implementation of the json data. Ideally it should be stored in a json file and should be retrieved by d3.json
  */
  data = [{
    "nodeData": {
      "number": "17",
      "size": 100
    },
    "subData": [
      {
        "nodeData": {
          "number": "16",
          "size": 25
        }
      },
      {
        "nodeData": {
          "number": "15",
          "size": 25
        }
      },
      {
        "nodeData": {
          "number": "14",
          "size": 25
        }
      },
      {
        "nodeData": {
          "number": "13",
          "size": 25
        },
        "subData": [
          {
            "nodeData": {
              "number": "12",
              "size": 100 / 6
            },
          },
          {
            "nodeData": {
              "number": "11",
              "size": 100 / 6
            }
          },
          {
            "nodeData": {
              "number": "10",
              "size": 100 / 6
            }
          },
          {
            "nodeData": {
              "number": "9",
              "size": 100 / 6
            }
          },
          {
            "nodeData": {
              "number": "8",
              "size": 100 / 6
            }
          },
          {
            "nodeData": {
              "number": "7",
              "size": 100 / 6
            },
            "subData": [
              {
                "nodeData": {
                  "number": "6",
                  "size": 100 / 6
                },
              },
              {
                "nodeData": {
                  "number": "5",
                  "size": 100 / 6
                }
              },
              {
                "nodeData": {
                  "number": "4",
                  "size": 100 / 6
                }
              },
              {
                "nodeData": {
                  "number": "3",
                  "size": 100 / 6
                }
              },
              {
                "nodeData": {
                  "number": "2",
                  "size": 100 / 6
                }
              },
              {
                "nodeData": {
                  "number": "1",
                  "size": 100 / 6
                }
              }
            ]
          }
        ]
      }]
  }]
</script>

Is a Pie chart the right approach?

Have you tried setting an offset angle when defining your arc pieces that are part of that pie row . Something like:

var arc = d3.svg.arc()
   .outerRadius((index + 1) * pieWidth - 1)
   .innerRadius(index * pieWidth)
   .startAngle((d) => {
       if( radius < outerRadiusSecondSlice && radius > innerRadiusSecondSlice) 
       {
           return d.startAngle + Math.PI/4 + offset;
       })
       else {
          return d.startAngle + Math.PI /4;
       }
     })
   .endAngle((d) => {
       if( radius < outerRadiusSecondSlice && radius > innerRadiusSecondSlice) 
       {
          return d.endAngle + Math.PI/4 + offset;
       })
       else {
          return d.endAngle + Math.PI /4;
       }
     })

You would have to define outerRadiusSecondSlice, innerRadiusSecondSlice, and offset appropriately.

If the structure of your data is nested, you may consider using a sunburst chart instead - the zoomable versions are pretty awesome. '''

d3 v5  https://observablehq.com/@d3/zoomable-sunburst
d3 v4  https://bl.ocks.org/vasturiano/12da9071095fbd4df434e60d52d2d58d
d3 v3  https://bl.ocks.org/WeikerWT/6008f1fc0a060a172b8ebec3e9e97ad7

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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