【D3.js 学习记录】——树形数据可视化

树形数据可视化

使用d3.js对层级数据进行可视化只需要考虑两步:

  • 数据预处理
  • data-join

width和height

  • Height:以本节点为根节点的树的高度

  • Width:与整棵树的根节点的路径长度

eg:
在这里插入图片描述

如11和15两个节点

  • 11节点的Height:4,Width:0
  • 15节点的Height:3,Width:1

数据处理

层级数据的数据预处理要分为两步

  • root1 = d3.hierarchy(data) 
    //第一步预处理,转化成层级结构
    // 返回的是层级结构的数据
    
  • root2 = d3.tree().size([innerHeight,innerWidth])(root1) //对层级结构进行空间上的划分/支配
    d3.tree().size()//返回的是函数,可以直接调用,传入层级结构数据可得最终结果
    

下面给出root1 和 root2的数据结构

root1 层级结构

在这里插入图片描述

root2 树形结构(添加了空间信息,‘x ,y 坐标’)

在这里插入图片描述

d3.hierarchy() 做了啥?
  • 保持数据的原始结构,并将输入层级数据转化成为d3中的hierarchy对象,同时引入下面的属性
    • height
    • depth
    • children
    • parent
    • data (原始数据的映射)
  • d3.hierarchy() 得到的数据结构可以作为一个 “ 中间结果 ”,继续输入到更多D3.js 提供的数据预处理的接口中
d3.tree() 做了啥?
  • 可以将处理好的数据 ‘进一步’ 预处理,将 hierarchy() 处理的节点映射到空间中特定的位置,加上x,y 坐标属性

绘图

画Path

这里有一个小Tips:

  • 如果想让树形图从上到下,那么设置d属性时,“x,y” 就与data中的 x,y 一致
  • 如果想让树形图从左到右,那么设置d属性时, “x , y” 就与data中的x,y相反
g.selectAll('path').data(root.links()).join('path')
    .attr('fill','none' )
    .attr('stroke', 'black')
    .attr('d', d3.linkHorizontal().x(d => d.y).y(d => d.x))
//看最后attr设置d时候,x与y 设置的值是相反的
画circle(结点)

circle的 rx,ry 要与path中的x ,y 对应

//画节点
g.selectAll('circle').data(root.descendants()).join('circle')
    .attr('cx', d => d.y)
    .attr('cy', d => d.x)
    .attr('fill',fill)
    .attr('stroke-width',3 )
    .attr('r', 6)
//root.descendants() 按照广度优先的原则将 树形结构数据压平,返回一个list
画结点的文字信息
//文字
g.selectAll('text').data(root.descendants()).join('text')
    .attr('font-size', '1em' )
    .attr('text-anchor', d => d.children ? 'end' : 'start')
    .attr('x', d => (d.children ? -6 : +6) + d.y) 
    .attr('y', d => d.x +5)
    .attr('dy', d => d.children ? 2 : 0 )
    .text( d => d.data.name)

//text-anchor 属性: d.children如果没有的话会为undifined,而undifined在逻辑表达式中为空。而如果有孩子,就让它从右往左扩展,不让孩子的路径遮盖text,如果没有孩子,就让它从左往右扩展

// x 与 y 的属性设置: 有孩子的节点和没有孩子的节点设置是不同的,为了避免path遮挡住文字

可视化代码

<!DOCTYPE html>
<html>
  <head>
    <title>Tree</title>
    <script src="./js/d3.min.js"></script>
  </head>
  <body>
    <svg width="1600" height="940" id="mainsvg" class="svgs" 
    style="display: block; margin: auto;"></svg>
    <script>
      const svg = d3.select('#mainsvg');
      const width = +svg.attr('width');
      const height = +svg.attr('height');
      const margin = {top: 50, right: 150, bottom: 50, left: 60};
      const innerWidth = width - margin.left - margin.right;
      const innerHeight = height - margin.top - margin.bottom;
      const g = svg.append('g')
      .attr('transform', `translate(${margin.left}, ${margin.top})`);
      let root;
      let color;



      const fill = d => {
      	if( d.depth == 0 ){
      		//根节点
      		return color(d.data.name);
      	}
      	while (d.depth >1 ){
      		//不是第二层
      		d = d.parent;
      	}
      	return color(d.data.name)
      }


      const render = function(){
      	color = d3.scaleOrdinal(d3.schemeCategory10)
      	// 比较简单的办法 ,动态分配配色

      	//下面是比较复杂的方法
      	// .domain(root.descendants().filter(d => d.depth<=1).map(d => d.data.name))
      	// .range(d3.schemeCategory10);


      	//画路径
      	g.selectAll('path').data(root.links()).join('path')
      	.attr('fill','none' )
      	.attr('stroke', 'black')
      	.attr('d', d3.linkHorizontal().x(d => d.y).y(d => d.x))
      	//如果把x和y 的值反过来就会变成一颗从上到下的树

      	//画节点
      	g.selectAll('circle').data(root.descendants()).join('circle')
      	.attr('cx', d => d.y)
      	.attr('cy', d => d.x)
      	.attr('fill',fill)
      	.attr('stroke-width',3 )
      	.attr('r', 6)
      	//root.descendants() 按照广度优先的原则将 树形结构数据压平,返回一个list


      	//文字
      	g.selectAll('text').data(root.descendants()).join('text')
      	.attr('font-size', '1em' )
      	.attr('text-anchor', d => d.children ? 'end' : 'start')
      	.attr('x', d => (d.children ? -6 : +6) + d.y) 
      	.attr('y', d => d.x +5)
      	.attr('dy', d => d.children ? 2 : 0 )
      	.text( d => d.data.name)

      	//text-anchor 属性: d.children如果没有的话会为undifined,而undifined在逻辑表达式中为空。而如果有孩子,就让它从右往左扩展,不让孩子的路径遮盖text,如果没有孩子,就让它从左往右扩展

      	// x 与 y 的属性设置: 有孩子的节点和没有孩子的节点设置是不同的,为了避免path遮挡住文字

      }

      d3.json('./data/games.json').then(data => {
      	root = d3.hierarchy(data);//第一步预处理,转化成层级结构
      	root = d3.tree().size([innerHeight,innerWidth])(root) ;  //对层级结构进行空间上的划分/支配
      	
      	render(); //data join

      })
    </script>
  </body>
</html>

可视化效果

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值