D3 V5开发力导向图
D3开始我在网上看到的资料都是V3居多的,公司项目需要用到v5的版本,找了好多资料,发现V3和V5的api的区别还是很大的,这里主要说下我用到的关系力导图。再说下我遇到的问题,和如何解决的。
有点差异的api
V3下初始化一个力
var force = d3.layout.force()//layout将json格式转化为力学图可用的格式
.nodes(d3.values(nodes))//设定节点数组
.links(links)//设定连线数组
.size([width, height])//作用域的大小
.linkDistance(180)//连接线长度
.charge(-1500)//顶点的电荷数。该参数决定是排斥还是吸引,数值越小越互相排斥
.on("tick", tick)//指时间间隔,隔一段时间刷新一次画面
.start();//开始转换
V5下初始化一个力导图
const simulation = d3.forceSimulation(nodes) //初始化一个力导向图
.force("link", d3.forceLink(links).id((d) => d.id).distance(200))//同上的设定连线数组 (ps:links一定要是一个数据类型)distance为连接线的长度
.force("charge", d3.forceManyBody().strength(-100))//charge设置引力
.force("center", d3.forceCenter(width / 2, height / 2));
d3的调用方法和jquery很相似,基本都是链式调用,很方便。选择器有两种 d3.select()
d3.selectAll()
d3.select获取到的是符合条件的第一个元素.
d3.selectAll返回的是符合条件的所有元素。
d3.forceSimulation(nodes) //这里是将这个nodes的数据进行转换,增加坐标等等,转换的结果如下:
id: "IFIND" index: 2 type: "resolved" vx: -0.000645327002392039 vy: -0.0016542362952343182 x: 958.4040054469376 y: 284.15898682862536
大概是这样的一个数据结构。
初始化完成数据后,需要添加连接线,箭头和需要的气泡还是什么可以自己增加,下边我大概贴下自己的使用的连接线、文字和气泡和箭头。
//箭头append到svg上
var marker = svg.append("marker")
.attr("id", "resolved")
//.attr("markerUnits","strokeWidth")//设置为strokeWidth箭头会随着线的粗细发生变化
.attr("markerUnits", "userSpaceOnUse")
.attr("viewBox", "0 -5 10 10")//坐标系的区域
.attr("refX", 32)//箭头坐标
.attr("refY", -1)
.attr("markerWidth", 12)//标识的大小
.attr("markerHeight", 12)
.attr("orient", "auto")//绘制方向,可设定为:auto(自动确认方向)和 角度值
.attr("stroke-width", 2)//箭头宽度
.append("path")
.attr("d", "M0,-5L10,0L0,5")//箭头的路径
.attr('fill', '#000000');//箭头颜色
增加下连接线。
var edges_line = svg.selectAll(".edgepath") //class用来占位
.data(links) //增加数据绑定
.enter() //导入数据
.append("path")
.style("stroke", function (d) {
var lineColor;
//根据关系的不同设置线条颜色
if (d.rela == "上位产品" || d.rela == "上游" || d.rela == "下位产品") {
lineColor = "#A254A2";
} else if (d.rela == "主营产品") {
lineColor = "#B43232";
}
return lineColor;
}).style("pointer-events", "none")
.style("stroke-width", 2)//线条粗细
.attr("marker-end", "url(#resolved)") //根据箭头id设置箭头显示
.attr('d', function (d) { ; return 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y }) //拼接下线条路径
.attr('class', 'edgepath')
.attr('id', function (d, i) { return 'edgepath' + i; });//根据箭头标记的id号标记箭头
设置显示气泡
var circle = svg.append("g").selectAll("circle")
.data(nodes)//表示使用force.nodes数据
.enter().append("circle")
.style("fill", function (node) {
var color;//圆圈背景色
var link = links[node.index];
if (node.name == link.source.name && link.rela == "主营产品") {
color = "#F6E8E9";
} else {
color = "#F9EBF9";
}
return color;
})
.style('stroke', function (node) {
var color;//圆圈线条的颜色
var link = links[node.index];
if (node.name == link.source.name && link.rela == "主营产品") {
color = "#B43232";
} else {
color = "#A254A2";
}
return color;
})
.attr("r", 28)//设置圆圈半径
.on("click", function (node) {
//单击时让连接线加粗
edges_line.style("stroke-width", function (line) {
console.log(line);
if (line.source.name == node.name || line.target.name == node.name) {
return 4;
} else {
return 0.5;
}
});
//d3.select(this).style('stroke-width',2);
})
.call(d3.drag().on("start", dragstarted) //开始drag函数
.on("drag", dragged) //drag中函数
.on("end",dragended));//将当前选中的元素传到drag函数中,使顶点可以被拖动
drag函数
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
对text元素设置颜色 填充等属性
var text = svg.append("g").selectAll("text")
.data(nodes)
//返回缺失元素的占位对象(placeholder),指向绑定的数据中比选定元素集多出的一部分元素。
.enter()
.append("text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")//在圆圈中加上数据
.style('fill', function (node) {
var color;//文字颜色
var link = links[node.index];
if (node.name == link.source.name && link.rela == "主营产品") {
color = "#B43232";
} else {
color = "#A254A2";
}
return color;
}).attr('x', function (d) {
// console.log(d.name+"---"+ d.name.length);
var re_en = /[a-zA-Z]+/g;
//如果是全英文,不换行
if (d.id.match(re_en)) {
d3.select(this).append('tspan')
.attr('x', 0)
.attr('y', 2)
.text(function () { return d.id; });
}
//如果小于四个字符,不换行
else if (d.id.length <= 4) {
d3.select(this).append('tspan')
.attr('x', 0)
.attr('y', 2)
.text(function () { return d.id; });
} else {
var top = d.id.substring(0, 4);
var bot = d.id.substring(4, d.id.length);
d3.select(this).text(function () { return ''; });
d3.select(this).append('tspan')
.attr('x', 0)
.attr('y', -7)
.text(function () { return top; });
d3.select(this).append('tspan')
.attr('x', 0)
.attr('y', 10)
.text(function () { return bot; });
}
//直接显示文字
/*.text(function(d) {
return d.name; */
});
设置tick函数
function tick() {
//path.attr("d", linkArc);//连接线
circle.attr("transform", (d) => {
return `translate(${d.x},${d.y})`
});//圆圈
text.attr("transform", d => {
return `translate(${d.x},${d.y})`
});//顶点文字
edges_line.attr("x", function (d) { return (d.source.x + d.target.x) / 2; });
edges_line.attr("y", function (d) { return (d.source.y + d.target.y) / 2; });
edges_line.attr('d', function (d) {
var path = 'M ' + d.source.x + ' ' + d.source.y + ' L ' + d.target.x + ' ' + d.target.y;
return path;
});
}
增加了这些基本就可以完成一个基本的力导向图。 完整版源码获取 pan.baidu.com/s/1VZvVjuW1… 提取码:dnu3