【问题标题】:Precalculate and set initial positions of nodes in D3.js在 D3.js 中预先计算和设置节点的初始位置
【发布时间】:2016-04-18 22:14:51
【问题描述】:

我正在尝试使用 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.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/ 如果你运行它几次并注意节点的起始位置,你可以看到它们是随机初始化的。

【问题讨论】:

  • 你能提供一个有用的小提琴吗?
  • 请看修改后的问题。
  • 真的,没人吗?我有点好奇……
  • @o-o 请看我的回答,希望能满足你的好奇心:P
  • @SebastianSmolorz 确实如此——非常感谢。

标签: javascript d3.js igraph force-layout


【解决方案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();

默认情况下布局会随机初始化节点。我发现解决这个问题的方法是添加一个 on tick 事件并稍后启动强制。

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 设置。

工作小提琴:https://jsfiddle.net/zbxbzmen/

【讨论】:

  • fiddle 无法正常工作。我改变了一些位置,但节点保持在以前的位置。
猜你喜欢
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
相关资源
最近更新 更多