我需要做一个"粘力布局"具有可拖动功能,并尝试在this link复制Mike Bostock的示例。因为作者在D3 v3中编写了该程序,所以我必须"升级"他的代码为D3 v4 。这意味着必须相应地更改d3-force和d3-drag语句。虽然原始示例中的逻辑流程很容易理解,但我仍然无法创建自己的版本(请参阅下面的代码)。问题:经过一段时间(2 - 3秒)后,节点被拖走但链接未更新。
我最初的想法主要集中在拖动功能(.call(拖动)),但后来我发现" tick"在上面提到的时间之后,函数不再运行(我通过在tick函数中放入一个count变量得到它,然后是console.log它)。到目前为止,我的思绪是空洞的,无法进一步探索。
问题出在哪里?
var width = 960,
height = 500;
var simulation = d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(-100))
d3.forceX(width)
d3.forceY(height)
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var drag = d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
var link = svg.selectAll(".link")
var node = svg.selectAll(".node")
d3.json("graph.json", function (error, graph) {
if (error) throw error;
simulation.nodes(graph.nodes)
.force("link", d3.forceLink(graph.links))
.on("tick", tick);
link = link.data(graph.links)
.enter().append("line")
.attr("class", "link");
node = node.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 12)
.on("dblclick", dblclick)
.call(drag)
});
var count = 0;
function tick() {
count++;
console.log(count);
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; })
}
function dblclick(d) {
d3.select(this).classed("fixed", d.fixed = false);
// console.log("Is clicking");
}
function dragstarted(d) {
d3.select(this).classed("fixed", d.fixed = true);
console.log("Is dragging");
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("active", false);
}
答案 0 :(得分:1)
在这种力导向图中有两件事导致了问题:
d.fixed
来修复节点1:修复节点
虽然您没有明确注意到这一点,但在图表更新链接数据的2-3秒内,节点在拖动后仍然会移动。
这是因为,与d3v3相反,您需要使用d.fx
和d.fy
手动修复坐标的x和y值; d.fixed
不再修复您的节点。对于您的代码,这看起来像:
function dragended(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
和
function dblclick(d) {
d.fx = null;
d.fy = null;
}
2:设置alpha衰减
这会导致图表冻结。由于alpha衰减导致图形稳定后,不再调用tick函数。此时,您的拖动发生时没有对链接进行任何更新,导致节点和链接之间的连接断开。
在d3v3中,默认情况下未定义alpha衰减,并且d3 可能会回退到不计算alpha衰减或使用零作为alpha衰减因子(导致相同的结果)。在d3v4中,alpha衰减设置为非零值:
如果指定了衰减,则将alpha衰减率设置为指定值 数字在[0,1]范围内并返回此模拟。如果腐烂不是 指定,返回当前的alpha衰减率,默认为 0.0228 ... = 1 - pow(0.001,1 / 300)其中0.001是默认的最小alpha。
alpha衰减率决定当前alpha的速度 插入所需的目标alpha;自默认 目标alpha为零,默认情况下,它控制的速度有多快 模拟冷却。衰减率越高,模拟就越稳定 更快,但有可能陷入局部最低限度;较低的价值 导致模拟运行时间更长,但通常会收敛 更好的布局。 让模拟永远在当前运行 alpha,将衰减率设置为零; 或者,设置目标alpha 大于最小alpha。
所以,你可以使用:
var simulation = d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(-100))
.alphaDecay(0);
(或者,将alphaTarget设置为适当的值,如上面文档引用中所述)。
总而言之,这看起来像this。