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