8

我在 D3 强制导向布局中有节点设置为 . 固定=真。如果我设置 .x 或 .y 值,节点本身不会移动到新位置。

这是我的功能:

function fixNode(idArray, locationX, locationY) {
    for ( x = 0; x < idArray.length; x++ ) {
        for ( y = 0; y < nodes.length; y++ ) {
            if (nodes[y].id == idArray[x]) {
                nodes[y].fixed = true;
                nodes[y].x = 50;
                nodes[y].y = 50;
                break;
            }
        }
    }
}

更新 1:

这是基于 Jason 建议的工作功能:

function fixNode(idArray, locationX, locationY) {
    for ( x = 0; x < idArray.length; x++ ) {
        for ( y = 0; y < nodes.length; y++ ) {
            if (nodes[y].id == idArray[x]) {
                nodes[y].fixed = true;
                nodes[y].x = 50;
                nodes[y].y = 50;
                nodes[y].px = 50;
                nodes[y].py = 50;
                break;
            }
        }
    }
    tick();
}
4

1 回答 1

14

力导向布局与实际渲染分离。通常你有一个刻度处理程序,它会为布局算法的每个“刻度”更新你的 SVG 元素的属性(关于解耦的好处是你渲染到 a<canvas>而不是其他东西)。

因此,要回答您的问题,您只需直接调用此处理程序即可更新 SVG 元素的属性。例如,您的代码可能如下所示:

var node = …; // append circle elements

var force = d3.layout.force()
    .nodes(…)
    .links(…)
    .on("tick", tick)
    .start();

function tick() {
  // Update positions of circle elements.
  node.attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}

因此,您可以在任何时候简单地调用tick()并更新元素位置。

您可能很想调用force.tick(),但这旨在用作 的同步替代方案force.start():您可以重复调用它,并且每次调用都会执行布局算法的一个步骤。但是,有一个内部alpha变量用于控制内部使用的模拟退火,一旦布局“冷却”,此变量将不再有效0,进一步调用force.tick()将无效。(诚​​然,如果不管冷却如何总是触发一个滴答事件可能会很好force.tick(),但这不是当前的行为)。

正如您在评论中正确指出的那样,如果您手动设置d.xand ,如果您希望节点保持在某个位置d.y,您还应该使用相同的值设置d.pxand 。d.py

于 2012-05-08T22:24:44.797 回答