Sunburst Tutorial

作者: 雷朝建 | 来源:发表于2018-04-21 12:28 被阅读0次

效果图

image.png

源码

https://github.com/leicj/d3/tree/master/src/components/sunburst

初始化变量

    const width = 500;
    const height = 500;
    const radius = Math.min(width, height) / 2;
    const color = d3.scaleOrdinal(d3.schemeCategory10);

不同于canvas, 在svg中我们需要手动设置绘图的宽度和高度. 这里我们也设置了饼状图的半径大小以及颜色(使用d3.schemeCategory10).

设定svg绘图区域

    const g = d3.select('svg')
      .attrs({ width, height })
      .append('g')
      .attr('transform', `translate(${width / 2},${height / 2})`);

设定svg的宽高后, 给予一个<g>用于绘图, 将其中心设置到绘图区域的中心位置.

格式化数据

    const partition = d3.partition()
      .size([2 * Math.PI, radius]);

d3.partition用于切割绘图区域. 这里由于是饼状图, 所以需要size函数设定其"宽高", 由于圆形的面积为2 * Math.PI * r, 所以2 * Math.PI为弧度, r为半径, 通过size函数则达到完全分割的状态.

    const root = d3.hierarchy(nodeData)
      .sum(d => d.size);

这里使用d3.hierarchy, 则nodeData的数据必须满足"父子层级"关系, 例如:

{
  "name": "Eve",
  "children": [
    {
      "name": "Cain"
    },
    {
      "name": "Seth",
      "children": [
        {
          "name": "Enos"
        },
        {
          "name": "Noam"
        }
      ]
    },
    {
      "name": "Abel"
    },
    {
      "name": "Awan",
      "children": [
        {
          "name": "Enoch"
        }
      ]
    },
    {
      "name": "Azura"
    }
  ]
}

根据sum函数来判断子节点的大小顺序. 经过partition(root)后, root会演化成一个可供计算的父子结构:


image.png

计算弧度及长度

    const arc = d3.arc()
      .startAngle(d => d.x0)
      .endAngle(d => d.x1)
      .innerRadius(d => d.y0)
      .outerRadius(d => d.y1);

由于经过partition后, root已经保存了每个节点的信息, 这里d.x0为开始的角度, d.x1为结束的角度. d.y0为开始的长度, d.y1为结束的长度.

绘图

    g.selectAll('g')
      .data(root.descendants())
      .enter().append('g').attr('class', 'node').append('path')
      .attr('display', d => d.depth ? null : 'none')
      .attr('d', arc)
      .style('stroke', '#fff')
      .style('fill', d => color((d.children ? d : d.parent).data.name))

通过root.descendants(), 我们将数据按size的大小顺序传入. 通过arc, 进行绘制图形, 而填充的颜色由name决定, 同一个父结构下的图形具有相同的颜色.

添加文本

    g.selectAll('.node')
      .append('text')
      .attr('transform', d => `translate(${arc.centroid(d)})rotate(${this.computeTextRotation(d)})`)
      .attr('dx', '-20')
      .attr('dy', '.5em')
      .text(d => d.parent ? d.data.name : '');

arc.centroid将计算arc的中心点, rotate进行角度的调整.
如果角度在120~270区间, 则字体要进行旋转, 否则为颠倒的字:

  computeTextRotation = (d) => {
    const angle = (d.x0 + d.x1) / Math.PI * 90;
    return (angle < 120 || angle > 270) ? angle : angle + 180;
  }

相关文章

网友评论

    本文标题:Sunburst Tutorial

    本文链接:https://www.haomeiwen.com/subject/mvfxlftx.html