业精于勤荒于嬉,行成于思毁于随
说明
目标:一个单人关系的可视化图表
实现思路:通过力导向图来实现,存在一个关键点master
,其他所有点都仅与它有关,master
点居中其他点根据关系权重分布在master
点四周,权重不同则与master
点距离不同,最终演示效果如下图所示:
实现
获取数据
首先我们先制造数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 var dataset={
nodes:[//节点
{name:"master",values:12},
{name:"das",values:25},
{name:"fd",values:39},
{name:"dsadsa",values:45},
{name:"htr",values:25},
{name:"vbcx",values:24},
{name:"ht",values:90},
{name:"nbv",values:80},
{name:"yrt",values:68},
{name:"jff",values:63},
{name:"nbv",values:25},
{name:"jyt",values:45},
{name:"mb",values:35},
{name:"jyt",values:78},
{name:"gtre",values:79},
{name:"bvc",values:25},
{name:"mjh",values:58},
{name:"ughf",values:86},
{name:"juy",values:79},
{name:"mjh",values:53},
{name:"njm",values:52},
],
edges:[//边
{ source:0,target:1},
{ source:0,target:2},
{ source:0,target:3},
{ source:0,target:4},
{ source:0,target:5},
{ source:0,target:6},
{ source:0,target:7},
{ source:0,target:8},
{ source:0,target:9},
{ source:0,target:10},
{ source:0,target:11},
{ source:0,target:12},
{ source:0,target:13},
{ source:0,target:14},
{ source:0,target:15},
{ source:0,target:16},
{ source:0,target:17},
{ source:0,target:18},
{ source:0,target:19},
{ source:0,target:20}
]
};
这是D3
力导向图布局接受的数据格式,其中nodes
代表点的数据,name
字段为master
的点为中心点,edges
代表边的数据,source
代表线的起点,target
代表线的终点。(边对象的source和target字段必须存在)
力布局
接下来就是添加力导向图布局,将我们的数据转换成适合D3生成力导向图的对象数组:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var force=d3.layout.force()
.nodes(dataset.nodes)//加载节点数据
.links(dataset.edges)//加载边数据
.size([w,h])//设置有效空间的大小
.linkDistance(function(d) {// 根据权重不同连接线段的长度也不同
if(d.target.values < 33) {
return 60;
} else if(d.target.values > 33 && d.target.values < 67) {
return 120;
} else if(d.target.values > 67) {
return 180;
}
})//连线的长度
.friction(0.6) // 摩擦阻力,数值越大阻力越小,范围[0.1],默认值为0.9
.charge(-100)//负电荷量,相互排斥设置的负值越大越排斥
.start();//设置生效
画线
创建作为连线的svg的line
元素1
2
3
4
5
6
7
8
9
10
11var edges=svg.selectAll("line")
.data(dataset.edges)
.enter()
.append("line")
.style("stroke",function(d){// 设置线的颜色
return colors(d.color);
})
.style("opacity", 0.5)
.style("stroke-width",function(d,i){//设置线的宽度
return 1;
});
画点
创建作为点的svg的circle
元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14var nodes=svg.selectAll("circle")
.data(dataset.nodes)
.enter()
.append("circle")
.attr("r",function(d){//设置圆点的半径,master为10,其他为5
if(d.name == "master") {
return 10;
}
return 5;
})
.style("fill",function(d){
return colors(d.weight*d.weight*d.weight);
})
.call(force.drag);//可以拖动
增加tick事件
tick
事件在D3中代表运动的每一步,与它类似的还有start:刚开始运动
,end:运动停止
,因此一般只要设置tick事件的监听器即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22force.on("tick",function(){
//边
edges.attr("x1",function(d){
return d.source.x;
})
.attr("y1",function(d){
return d.source.y;
})
.attr("x2",function(d){
return d.target.x;
})
.attr("y2",function(d){
return d.target.y;
});
//节点
nodes.attr("cx",function(d){
return d.x;
})
.attr("cy",function(d){
return d.y;
});
控制中心点不动
我们为了做到控制中心点不动需要在每次计算位置是重置中心点的坐标为[w/2,h/2],所以我们在tick事件中添加以下代码:
1
2dataset.nodes[0].x = w/2;
dataset.nodes[0].y = h/2;
这样我们就能保证无论其他点如何移动,中心点始终在svg页面中心保持不动。
完整代码
1 | <!DOCTYPE html> |