javascript - 在 D3.js 中预计算并设置节点的初始位置
我正在尝试使用 igraph 预先计算稳定的力导向图的位置,并将它们传入我的 d3.js 图中。这是因为我将使用的数据集非常大,这意味着如果在客户端完成完整的力计算,我不能指望客户端不会冻结。我已经以 JSON 格式得到了这些位置,并使用线性比例尺以便在 d3.js 中使用它们。
var positions =
{"positions": [{"x":"-68.824367374", "y": "-6.10824525755"},
{"x":"-80.8080803911", "y": "-3.38997541264"},
{"x":"6.75334817585", "y": "-49.6040729697"},
{"x":"14.6608797291", "y": "-81.8897019921"},
....
var force = d3.layout.force()
.charge(-100)
.linkDistance(3)
.size([width, height])
.nodes(data.nodes)
.links(data.links)
.start();
var posX = d3.scale.linear()
.range([0,960])
.domain([-125,120]);
var posY = d3.scale.linear()
.range([0,500])
.domain([-125,125]);
这就是我尝试做这件事的方式。我尝试过 px 和 py,但结果还是一样。好像这段代码从未被运行过。如果我在下面看到的地方加入 console.log,值也不会被打印出来。无论我把这段代码放在启动 force 之前还是之后,结果都是一样的。
force.on("start", function() {
node
.data(positions.positions)
.attr("cx", function(d) {
console.log(posX(d.x));
return posX(d.x);
})
.attr("cy", function(d) {
return posY(d.y);
})
});
为什么 on start 事件没有设置我的节点的初始位置?它们似乎仍然是随机初始化的。或者,有什么好的方法可以预先计算 d3.js 力导向图的稳定状态?我看过在 Phantomjs 上做这件事,但放弃了。
感谢您抽出时间阅读我的问题!
编辑
这是一个简化的示例:https://jsfiddle.net/xp0zgqes/ 如果你多运行几次并注意节点的起始位置,你可以看到它们是随机初始化的。
答案#1
真的不喜欢自己回答自己的问题,但我认为这会非常有用。首先,(这可能只适用于我的情况)如果初始位置数据来自与节点/链接数据不同的数据对象,那么将它们合并后,你就不必绑定两个数据源(或者你比我更聪明,直接创建包含 x 和 y 位置的原始 json 对象)。在我的情况下:
for (var i = 0; i < data.nodes.length; i++){
data.nodes[i].x = posX(positions.positions[i].x);
data.nodes[i].y = posY(positions.positions[i].y);
data.nodes[i].newAttribute = value;
}
多亏了 JSON 的魔力,向数据添加新属性是如此简单,这非常好,例如,如果你希望你的节点是固定的。
问题似乎出在 force.start() 调用上。如果在初始化力时这样调用:
var force = d3.layout.force()
.charge(-100)
.linkDistance(3)
.size([width, height])
.nodes(data.nodes)
.links(data.links)
.start();
布局默认会随机初始化节点。我找到的解决方法是添加一个计时事件,然后稍后再启动力。
var force = d3.layout.force()
.charge(-100)
.linkDistance(3)
.size([width, height])
.nodes(data.nodes)
.links(data.links)
.on("tick", tick);
force.start(); //Note, not chained
//Standard code that goes in the on.tick event
function tick() {
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; });
}
瞧!我们现在有了一个功能齐全的力导向图,初始位置已从 JSON 设置。
可用的 fiddle:https://jsfiddle.net/zbxbzmen/
