我的d3.js力导向图如何解决数据在首次渲染时,所有节点剧烈抖动,为什么抖动,(特别剧烈!!!)
force.on("tick", function () {
if(force.alpha()<=0.05){ // 足够稳定时,才渲染一次
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; });
node.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
force.stop(); // 渲染完成后立即停止刷新
}
});
阅读了一下官方文档 ,发现问题出来 tick
上。
force.start() 后,有一个计时器不停地触发 tick 直到所有节点最终受力平衡稳定下来。
可以理解为,有个计时器不停在打点,每打一次点需要触发一次 tick() 里的动作。而 tick() 的默认动作是重绘所有节点和连线位置。因为图形渲染需要时间长,渲染的次数又多,所以需要等很长时间,且会抖动,你将源码进行如上的修改,应该就能解决这个问题。
force.on("tick", function () {
edges_path.attr("d", function (d) {
var tan = Math.abs((d.target.y - d.source.y) / (d.target.x - d.source
.x)); //圆心连线tan值
var x1 = d.target.x - d.source.x > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius / (
tan * tan + 1)) + d.source.x :
d.source.x - Math.sqrt(d.sourceRadius * d.sourceRadius / (tan * tan +
1)); //起点x坐标
var y1 = d.target.y - d.source.y > 0 ? Math.sqrt(d.sourceRadius * d.sourceRadius *
tan * tan / (tan * tan + 1)) + d.source.y :
d.source.y - Math.sqrt(d.sourceRadius * d.sourceRadius * tan * tan / (tan *
tan + 1)); //起点y坐标
var x2 = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt(d.targetRadius * d
.targetRadius / (1 + tan * tan)) :
d.target.x + Math.sqrt(d.targetRadius * d.targetRadius / (1 + tan *
tan)); //终点x坐标
var y2 = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius * d
.targetRadius * tan * tan / (1 + tan * tan)) :
d.target.y + Math.sqrt(d.targetRadius * d.targetRadius * tan * tan / (1 + tan *
tan)); //终点y坐标
if (d.target.x - d.source.x == 0 || tan == 0) { //斜率无穷大的情况或为0时
y1 = d.target.y - d.source.y > 0 ? d.source.y + d.sourceRadius : d.source.y - d
.sourceRadius;
y2 = d.target.y - d.source.y > 0 ? d.target.y - d.targetRadius : d.target.y + d
.targetRadius;
}
// 防报错
if (!x1 || !y1 || !x2 || !y2) {
return
}
if (d.linknum == 0) { //设置编号为0的连接线为直线,其他连接线会均分在两边
d.x_start = x1;
d.y_start = y1;
d.x_end = x2;
d.y_end = y2;
return 'M' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2;
}
var a = d.sourceRadius > d.targetRadius ? d.targetRadius * d.linknum / 3 : d
.sourceRadius * d.linknum / 3;
var xm = d.target.x - d.source.x > 0 ? d.source.x + Math.sqrt((d.sourceRadius * d
.sourceRadius - a * a) / (1 + tan * tan)) :
d.source.x - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) / (1 + tan *
tan));
var ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt((d.sourceRadius * d
.sourceRadius - a * a) * tan * tan / (1 + tan * tan)) :
d.source.y - Math.sqrt((d.sourceRadius * d.sourceRadius - a * a) * tan * tan / (
1 + tan * tan));
var xn = d.target.x - d.source.x > 0 ? d.target.x - Math.sqrt((d.targetRadius * d
.targetRadius - a * a) / (1 + tan * tan)) :
d.target.x + Math.sqrt((d.targetRadius * d.targetRadius - a * a) / (1 + tan *
tan));
var yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt((d.targetRadius * d
.targetRadius - a * a) * tan * tan / (1 + tan * tan)) :
d.target.y + Math.sqrt((d.targetRadius * d.targetRadius - a * a) * tan * tan / (
1 + tan * tan));
if (d.target.x - d.source.x == 0 || tan == 0) { //斜率无穷大或为0时
ym = d.target.y - d.source.y > 0 ? d.source.y + Math.sqrt(d.sourceRadius * d
.sourceRadius - a * a) : d.source.y - Math.sqrt(d.sourceRadius * d
.sourceRadius - a * a);
yn = d.target.y - d.source.y > 0 ? d.target.y - Math.sqrt(d.targetRadius * d
.targetRadius - a * a) : d.target.y + Math.sqrt(d.targetRadius * d
.targetRadius - a * a);
}
var k = (x1 - x2) / (y2 - y1); //连线垂线的斜率
var dx = Math.sqrt(a * a / (1 + k * k)); //相对垂点x轴距离
var dy = Math.sqrt(a * a * k * k / (1 + k * k)); //相对垂点y轴距离
if ((y2 - y1) == 0) {
dx = 0;
dy = Math.sqrt(a * a);
}
if (a > 0) {
var xs = k > 0 ? xm - dx : xm + dx;
var ys = ym - dy;
var xt = k > 0 ? xn - dx : xn + dx;
var yt = yn - dy;
} else {
var xs = k > 0 ? xm + dx : xm - dx;
var ys = ym + dy;
var xt = k > 0 ? xn + dx : xn - dx;
var yt = yn + dy;
}
//记录连线起始和终止坐标,用于定位线上文字
d.x_start = xs;
d.y_start = ys;
d.x_end = xt;
d.y_end = yt;
return 'M' + xs + ' ' + ys + ' L ' + xt + ' ' + yt;
});
//更新连接线上文字的位置
edges_text.attr("transform", function (d) {
// 防止报错
if (!d.x_start || !d.y_start || !d.x_end || !d.y_end) {
return
}
return "translate(" + (d.x_start + d.x_end) / 2 + "," + ((+d.y_start) + (+d
.y_end)) / 2 +
")" + " rotate(" + Math.atan((d.y_end - d.y_start) / (d.x_end - d.x_start)) *
180 / Math.PI + ")";
});
//更新结点图片和文字
circle.attr("cx", function (d) {
return d.x
});
circle.attr("cy", function (d) {
return d.y
});
nodes_text.attr("x", function (d) {
return d.x
});
nodes_text.attr("y", function (d) {
return d.y
});
});
您好,我是有问必答小助手,您的问题已经有小伙伴解答了,您看下是否解决,可以追评进行沟通哦~
如果有您比较满意的答案 / 帮您提供解决思路的答案,可以点击【采纳】按钮,给回答的小伙伴一些鼓励哦~~
ps:问答VIP仅需29元,即可享受5次/月 有问必答服务,了解详情>>>https://vip.csdn.net/askvip?utm_source=1146287632