目录
- 1. 不同D3版本差异
- 2. D3 V4版本绘制力导向图基本流程
- 3. 跨域问题
- 现象
- 原因
- 解决办法
- 4. 异步赋值
- 现象
- 原因
- 解决办法
1. 不同D3版本差异
V3:通过d3.layout.force()将节点、连接线的数据转换成d3力导向图能够使用的数据结构
var force = d3.layout.force().nodes(nodes)
.links(lines)
.size([width, height])
.linkDistance(100)
.charge(-1200)
.start()
.on("tick", function () {
//具体的方法
});
V4:通过 d3.forceSimulation()定义关系图,包括设置边link、排斥电荷charge、关系图中心点
var simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).distance(200))
.force("charge",d3.forceManyBody().strength(-100))
.force("center",d3.forceCenter(width/2, height/2));
simulation.on("tick",function(){
//具体的方法
});
// 生成节点
simulation.nodes(nodes).on("tick", ticked);
//生成边
simulation.force("link")
.links(links)
.distance(d => { return 200 }); //每一边的长度
2. D3 V4版本绘制力导向图基本流程
- 创建svg绘图:svg是一种矢量图格式,相当于创建一个画图的容器,图中的所有内容都在这个svg中
var svg = d3.select("#svg1") //select中的内容是需要绑定的html标签
- 创建节点、连线、文字、箭头等图形元素:前提是已经导入了节点和边的数据,以数组的形式分别记录
//绘制边
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links) //边数组
.enter()
.append("line")
.attr("stroke-width", 2) //线段宽度,需要再加一个线段颜色
.style("stroke", '#000000'); //设置填充颜色
//绘制边上文字
var linksText = svg.append("g")
.selectAll("text")
.data(links)
.enter()
.append("text")
.text(function(d){return d.type;}) //显示内容是边的类型属性
//箭头
var marker = svg.append("marker")
.attr("id", "resolved")
.attr("markerUnits","userSpaceOnUse")
.attr("viewBox", "0 -5 10 10")//坐标系的区域
.attr("refX",34)//箭头坐标
.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 node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes) //节点数组
.enter()
.append("circle")
.attr("r", function(d) {return 15}) // 设置圆圈半径
.attr("fill", '#000000') //设置填充颜色
.attr("stroke", "none")
.attr("id", d => d.id) //设置id
.call(d3.drag() //设置拖拽
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
//绘制描述节点的文字
var nodesText = svg.append('g')
.selectAll("text")
.data(nodes)
.enter()
.append("text")
.style("fill", "black")
.attr("dx", 20)
.attr("dy", 8)
.text(function (d) {return d.name;}); //设置节点文字是节点的名字属性
- 创建力导向图对象:使用d3.forceSimulation()定义力导向图,包括设置边link、排斥电荷charge、关系图中心点
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(d => {return d.id}))
.force("charge", d3.forceManyBody().strength(-30)) //电荷排斥,strength为负是排斥,为正是吸引
.force("center", d3.forceCenter(width / 2, height / 2)) //中心位置
.force("collision", d3.forceCollide(20)) // 碰撞检测
- 将节点、关系元素导入力导向图中
// 生成节点
simulation.nodes(nodes).on("tick", ticked);
//生成边
simulation.force("link")
.links(links)
.distance(d => { return 200 }); //每一边的长度
- 确定节点、边、文字、箭头的位置
// ticked()函数确定link线的起始点x、y坐标 node确定中心点 文本通过translate平移变化
function ticked() {
link
.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;})
.attr("marker-end", "url(#resolved)");
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;});
node
.attr("cx", function(d) {return d.x;})
.attr("cy", function(d) {return d.y;});
nodesText
.attr("x", function (d) {return d.x;})
.attr("y", function (d) {return d.y;});
}
- 设置拖拽,鼠标移动等事件
// 拖动函数代码
var dragging = false;
// 开始拖动并更新相应的点
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
dragging = true;
}
// 拖动进行中
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;
dragging = false;
}
// 鼠标选中节点事件
$('#svg1').on('mouseenter', '.nodes circle', function(event) {
//添加事件内容
});
// 鼠标移开节点事件
$('#svg1').on('mouseleave', '.nodes circle', function(event) {
//添加事件内容
});
3. 跨域问题
现象
使用d3.json()读取json文件数据时,直接用浏览器运行的话会报跨域错误
原因
跨域指的是不同域之间互相请求资源,比如a.com无法操作b.com下的内容。常规来说写了一个前端页面直接就用默认浏览器打开运行了,此时浏览器的地址栏显示的是你的html文件在你电脑上的地址。需要用一个服务器来存放json文件,通俗说就说要用localhost这样的地址去运行你的程序。
解决办法
整体的思路都是将文件和代码放在一个服务器中去请求,以下提供两个思路:
- 使用nodejs提供本地服务器
- IDE可能会存在自带的本地服务器,通过该方式运行程序。以vs code为例,可以下载一个叫做Live Server的插件,通过右键选择Open with Live Server.即可
4. 异步赋值
现象
使用d3.json()读取数据时,将数据内容赋值到变量中,在d3.json()函数内能正常赋值,函数结束后变量值为undefined或默认值
原因
d3.json()采用异步的方式读取数据,导致赋值了但没有更新,从而在函数外没有赋值成功
解决办法
采用JQuery读取json文件,并且设置参数async为false,这样便是采用同步的方式读取数据。
$.ajax({
url: path, //json文件的地址
type: "GET",
dataType: "json",
async: false, //不采用异步方式
success:
function (data) { //进行赋值操作
nodeConfig = data.node
relationshipConfig = data.relationship
dataPath = data.dataPath
}
});