数据可视化【十一】树状图

Constructing a node-link tree visualization

首先将节点之间的连线画出来。
使用json函数读取文件以后,使用hierarchy等函数得到连线的数组,然后绑定这个数组,给每个元素添加一个path,绘画使用的是一个函数linkHorizontal(因为这里是水平的树状图,如果你想绘制垂直的也可以使用linkVertical,需要注意的是,水平的需要交换每个连线的x和y,垂直的不需要)
index.js

json('data.json')
	.then(data =>{
  	const root = hierarchy(data);
  	const links = treeLayout(root).links();
  
  	const linkPathGenerator = linkHorizontal()
    	.x(d => d.y)
    	.y(d => d.x)
    //上面的x和y进行了替换,是因为我们想要绘制水平的树状图,如果使用垂直的,x和y应该是对应的
  	g.selectAll('path').data(links)
  		.enter().append('path')
  			.attr('d', linkPathGenerator);
}

style.css

path {
	fill: none;
  stroke: #f7a4a4;
}

Adding text labels to the nodes

通过root.descendants获得每个节点的位置数组,绑定这个数组以后添加text,同样需要注意水平的xy需要分开。然后使用一些技巧使得文字变得更加好看

const treeLayout = tree()
	.size([Height, Width]);
	
json('data.json')
	.then(data =>{
  	const root = hierarchy(data);
  	const links = treeLayout(root).links();
  
  	const linkPathGenerator = linkHorizontal()
    	.x(d => d.y)
    	.y(d => d.x)
    //上面的x和y进行了替换,是因为我们想要绘制水平的树状图,如果使用垂直的,x和y应该是对应的
  	g.selectAll('path').data(links)
  		.enter().append('path')
  			.attr('d', linkPathGenerator);
  	g.selectAll('text').data(root.descendants())
  		.enter().append('text')
  			.attr('x', d => d.y)
  			.attr('y', d => d.x)
  			.text(d => d.data.data.id);
	});

Using the Margin Convention(约定)

为了让文字布局更加好看,我们需要设置Margin来设置边框

const margin = {top:0, right: 70, bottom: 0, left:90};
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;

const treeLayout = tree()
	.size([innerHeight, innerWidth]);

const zoomG = svg
	.attr('width', width)
	.attr('height', height)
  .append('g');

const g = zoomG.append('g')
.attr('transform',`translate(${margin.left},${margin.top})`);

然后后面都在g上添加元素即可。这里设置了两层g实际上是为了后面放大缩小的时候使用

Tweaking(调整) label alignment(队列) and size

我们还需要设置标签的位置,标签的字体大小:
index.js

g.selectAll('text').data(root.descendants())
  		.enter().append('text')
  			.attr('x', d => d.y)
  			.attr('y', d => d.x)
  			.attr('dy', '0.32em')//使得节点被线从中间穿过
  			.attr('text-anchor', d => d.children ? 'middle' : 'start')//将文字放在中间
  			.attr('font-size', d => 3.2-d.depth + 'em')	//使得文字大小随层数递减
  			.text(d => d.data.data.id);

style.css

text {
	text-shadow:
/*  给标签添加白色的阴影,这样就不会被线挡住    */
    -1px -1px 3px white,
    -1px 1px 3px white,
    1px -1px 3px white,
    1px 1px 3px white;
  pointer-events: none;	
/*   鼠标经过文字的时候不会变成可编辑的样子(因为本来就是不可编辑的) */
}

Panning & Zooming

这个和以前一样,在call函数里面添加zoom函数:
index.js

svg.call(zoom().on('zoom',() =>{
	zoomG.attr('transform', event.transform);
}));

Curran说弄两层g这样就可以解决放大再缩小以后边框丢失的问题,但是我发现好像并没有什么卵用。。。

Using a custom font

选择一个好看的字体也很重要,首先在Google Fonts里面找到一个喜欢的字体,然后点击select
在这里插入图片描述
然后把link放在html文件里面,后面的字体放在对应的选择器里面就可以了。

效果图:在这里插入图片描述
在这里插入图片描述
代码地址:https://vizhub.com/Edward-Elric233/706152caf5ca4aae992cc371f2d5891a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值