d3绘制树状图

使用d3中提供的d3.tree()API。

const data = {
  name: '中国',
  children: [
    {
      name: '浙江',
      children: [
        { name: '杭州', value: 100 },
        { name: '宁波', value: 100 },
        { name: '温州', value: 100 },
        { name: '绍兴', value: 100 }
      ]
    },
    {
      name: '广西',
      children: [
        {
          name: '桂林',
          children: [
            { name: '秀峰区', value: 100 },
            { name: '叠彩区', value: 100 },
            { name: '象山区', value: 100 },
            { name: '七星区', value: 100 }
          ]
        },
        { name: '南宁', value: 100 },
        { name: '柳州', value: 100 },
        { name: '防城港', value: 100 }
      ]
    },
    {
      name: '黑龙江',
      children: [
        { name: '哈尔滨', value: 100 },
        { name: '齐齐哈尔', value: 100 },
        { name: '牡丹江', value: 100 },
        { name: '大庆', value: 100 }
      ]
    },
    {
      name: '新疆',
      children:
        [
          { name: '乌鲁木齐' },
          { name: '克拉玛依' },
          { name: '吐鲁番' },
          { name: '哈密' }
        ]
    }
  ]
}

const marge = { top: 50, bottom: 0, left: 10, right: 0 };

const width = window.innerWidth,
  height = window.innerHeight,
  svg = d3.select('body').append('svg').attr('width', width).attr('height', height);

const g = svg.append('g').attr('transform', `translate(${marge.top}, ${marge.left})`)

//指定树的层次数据结构
const hierarchyData = d3.hierarchy(data).sum(d => d.value)

//创建一个树布局
const tree = d3.tree().size([width / 2, height / 2]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth)
//使用指定的hierarchy进行布局,并附加node.x和node.y两个属性
const treeData = tree(hierarchyData)
const nodes = treeData.descendants(),
  links = treeData.links()

//贝塞尔曲线生成器
const bezier_curve_generator = d3.linkHorizontal().x(d => d.y).y(d => d.x)

//连线
g.append('g').selectAll('path').data(links).enter()
  .append('path').attr('d', d => {
    const start = { x: d.source.x, y: d.source.y }
    const end = { x: d.target.x, y: d.target.y }
    return bezier_curve_generator({ source: start, target: end })
  })
  .attr('fill', 'none')
  .attr('stroke', '#444')
  .attr('stroke-width', 1)

//节点和对应文字分组
const gs = g.append('g').selectAll('g').data(nodes).enter().append('g')
  .attr('transform', d => `translate(${d.y}, ${d.x})`)

//绘制节点
gs.append('circle').attr('r', 6).attr('fill', 'white').attr('stroke', '#555').attr('stroke-width', 1)
.on('click', nodeClick)
gs.append('circle').attr('r', 2).attr('fill', 'white').attr('stroke', '#555').attr('stroke-width', 1)
  .on('click', nodeClick)

//文字
gs.append('text').attr('x', d => d.children ? -40 : 8).attr('y', -5).attr('dy', 10).text(d => d.data.name)

function nodeClick() {
  d3.select(this).transition().attr('r', 8)
}

运行效果如下

See the Pen JaLbXm by Leevare (@leevare) on CodePen.

代码实现参考自:https://blog.csdn.net/qq_34414916/article/details/80038989

如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注