力导布局图:是一种用来呈现复杂关系网络的图表。在力导布局图中,系统中的每个节点都可以看成是一个放电粒子,粒子间存在某种斥力。同时,这些粒子间被它们之间的“边”所牵连,从而产生引力。系统中的粒子在斥力和引力的作用下,从随机无序的初态不断发生位移,逐渐趋于平衡有序的终态。
**
1.数据集
**
由nodes和edges两个数组组成,数组中的元素是一个个的对象。
nodes数组例如:
nodes代表节点的必要信息,name是结点的名字,size是用来表示节点的大小的值。(size可以不设置,只有name即可)edges数组例如:
edges 表示的是节点之间是否连线,source是连线的起点,target是连线的终点,其中,nodes中对象的下标对应着source和target的值。
**
2.创建一个力导向图的模拟器
**
var forceSimulation = d3.forceSimulation()
.force("link", d3.forceLink())
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter());
此时的数据还不可使用,需要使用forceSimulation生成节点和边的可用数据。
//生成节点数据
forceSimulation.nodes(nodes)
.on("tick", ticked);
//生成边数据
forceSimulation.force("link")
.links(edges)
.distance(150)
//设置图形的中心位置
forceSimulation.force("center")
.x(w / 2)
.y(h / 2);
//在浏览器的控制台输出
console.log(nodes);
console.log(edges);
这时,输出的数据nodes和edges都发生了改变:
nodes数据多出了x,y和index值。
edges数据多出了vx,vy,x,y值。
力导向图的动效实现本质就是每一帧都重新渲染图中节点的位置(x,y), 节点的位置(x,y)是由节点上一帧所处的位置(x,y)+速度(vx,vy)所决定的。而速度就是通过力学模型所计算出来的。
**
3.绘制力导向图
**
绘制力导向图需要绘制三种图形元素:
- line,线段,表示连线。
- circle,圆,表示节点。
- text,文字,描述节点信息。
**
//绘制边
var links = g.append("g")
.selectAll("line")
.data(edges)
.enter()
.append("line")
.attr("stroke", function (d, i) {
return colorScale(2); //边的颜色
})
.attr("stroke-width", 1);
//边上文字
var linksText = g.append("g")
.selectAll("text")
.data(edges)
.enter()
.append("text")
.text(function (d) {
return d.relation;
})
//建立用来放在每个节点和对应文字的分组<g>
var gs = g.selectAll(".circleText")
.data(nodes)
.enter()
.append("g")
.attr("transform", function (d, i) {
var cirX = d.x;
var cirY = d.y;
return "translate(" + cirX + "," + cirY + ")";
})
.call(d3.drag()
.on("start", started)
.on("drag", dragged)
.on("end", ended)
);
//绘制节点
gs.append("circle")
.attr("r", function (d, i) { //圆圈半径
return d.size;
})
.attr("fill", function (d, i) {
return colorScale(d.size);
})
//文字
gs.append("text")
.attr("x", -25)
.attr("y", -5)
.attr("dy", 10)
.text(function (d) {
return d.name;
})
4.节点拖动事件监听
**
力导向图布局 force 有一个监听事件 tick。意为每进行到一个时刻,都要调用它的监听函数。以下为示例代码:
function ticked() {
links
.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; });
linksText
.attr("x", function (d) {
return (d.source.x + d.target.x) / 2;
})
.attr("y", function (d) {
return (d.source.y + d.target.y) / 2;
});
gs
.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
}
效果展示: