D3.js v5.0 打包图

在这里插入图片描述
在这里插入图片描述
数据结构:

{
  "name": "flare",
  "children": [
    {
      "name": "",
      "children": [
        {
          "name": "",
          "children": [
            {
              "name": "",
              "value": 3938
            },
          ]
        },
      ]
    }
  ]
} 

大概的思路简单来说就是 —创建pack布局—转换数据—画圆—添加文字—添加mouse事件

/* eslint-disable no-param-reassign */
import * as d3 from 'd3';

export default function zoomPacking(id, data) {
  (() => {
    d3.select(id)
      .selectAll('svg')
      .remove();
  })();
  /** 宽 */
  const width = 500;
  /** 高 */
  const height = 500;
  const color = d3
    .scaleLinear()
    .domain([0, 5])
    .range(['hsl(152,80%,80%)', 'hsl(228,30%,40%)'])
    .interpolate(d3.interpolateHcl);
    
  const pack = dataset =>
    d3
      .pack()
      .size([width, height])
      .padding(3)(
      d3
        .hierarchy(dataset)
        .sum(d => d.value)
        .sort((a, b) => b.value - a.value)
    );

  const root = pack(data);
  let focus = root;
  let view;

  const svg = d3
    .select(id)
    .append('svg')
    .attr('viewBox', `-${width / 2} -${height / 2} ${width} ${height}`)
    .attr('width', width)
    .attr('height', height)
    .style('display', 'block')
    .style('background', color(0))
    .style('cursor', 'pointer')
    .style('margin', '100 100px')
    .on('click', () => zoom(root));

  const node = svg
    .append('g')
    .selectAll('circle')
    .data(root.descendants().slice(1))
    .join('circle')
    .attr('fill', d => (d.children ? color(d.depth) : 'white'))
    .attr('pointer-events', d => (!d.children ? 'none' : null))
    .on('mouseover', function() {
      d3.select(this).attr('stroke', '#000');
    })
    .on('mouseout', function() {
      d3.select(this).attr('stroke', null);
    })
    .on('click', d => focus !== d && (zoom(d), d3.event.stopPropagation()));

  const label = svg
    .append('g')
    .style('font', '10px sans-serif')
    .attr('pointer-events', 'none')
    .attr('text-anchor', 'middle')
    .selectAll('text')
    .data(root.descendants())
    .join('text')
    .style('fill-opacity', d => (d.parent === root ? 1 : 0))
    .text(d => d.data.name);

  zoomTo([root.x, root.y, root.r * 2]);

  function zoomTo(v) {
    const k = width / v[2];

    view = v;

    label.attr('transform', d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);
    node.attr('transform', d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);
    node.attr('r', d => d.r * k);
  }

  function zoom(d) {
    focus = d;

    const transition = svg
      .transition()
      .duration(d3.event.altKey ? 7500 : 750)
      .tween('zoom', () => {
        const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]);
        return t => zoomTo(i(t));
      });

    label
      .filter(() => {
        return d.parent !== focus;
      })
      .transition(transition)
      .style('fill-opacity', a => (a.parent === focus ? 1 : 0));
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值