动态地向d3.js力导向图中添加节点

3

我在使用d3.js力导向图动态添加节点时遇到了问题,想知道是否有人能够帮我解决这个问题。

我的问题是我希望tick函数可以转换图上的所有节点而不仅仅是新添加的节点。

以下是我用于添加节点和处理转换的函数:

// Function to handle tick event
function tick() {
     tick_path.attr("d", function(d) {
     var dx = d.target.x - d.source.x,
     dy = d.target.y - d.source.y,
     dr = Math.sqrt(dx * dx + dy * dy);
    return "M" + 
        d.source.x + "," + 
        d.source.y + "L" + 
        d.target.x + "," + 
        d.target.y;
     });

     tick_node.attr("transform", function(d) { 
          return "translate(" + d.x + "," + d.y + ")"; });
 }


 /**
   * Append nodes to graph.
   */
 function addNodes2Graph(){

    // define the nodes
       // selection will return none in the first insert
       // enter() removes duplicates (assigning nodes = nodes.enter() returns only the non-duplicates)
    var nodes = viz.selectAll(".node") 
    .data(g_nodes)
    .enter().append("g") 
    .on("click", nodeClick)
    .call(force.drag);

    // From here on, only non-duplicates are left
    nodes
        .append("circle")
        .attr("r", 12)
        .attr("class", "node");

    nodes.append("svg:image")
    .attr("class", "circle")
    .attr("xlink:href", "img/computer.svg")
    .attr("x", "-8px")
    .attr("y", "-8px")
    .attr("width", "16px")
    .attr("height", "16px");

   // add the text 
    nodes.append("text")
    .attr("x", 12)
    .attr("dy", ".35em")
        .text(function(d) { return d.ip; });


     return nodes;
 }

 // Execution (snippet)

 // Add new nodes
 tick_node = addNodes2Graph();
 // Add new paths
 tick_path = addPaths2Graph();


 // Restart graph
 force
.nodes(g_nodes) // g_nodes is an array which stores unique nodes
.links(g_edges) // g_edges stores unique edges
.size([width, height])
.gravity(0.05)
.charge(-700)
.friction(0.3)
.linkDistance(150)
.on("tick", tick)
.start();

我认为问题在于我只从addNodes2Graph中得到了非重复的结果,然后在tick函数中使用这些结果,但我不确定如何做到这一点而不向图表中添加重复的节点。
目前,要么将重复的元素添加到图形中,要么仅在tick函数中转换新节点。
非常感谢您提前的帮助。
1个回答

5
看起来你只是向DOM添加了节点,而没有向力布局添加节点。总结一下,以下是向力布局添加节点的步骤:
  • 将元素添加到力布局用于其节点的数组中。这需要是最初传递的相同数组,即如果要实现平滑行为,则不能创建新数组并传递它。修改force.nodes()应该可以正常工作。
  • 对于链接也是如此。
  • 使用新数据使用.data().enter()添加新的DOM元素。
  • 不需要更改tick函数,因为在其他地方已经添加了节点和DOM元素。
添加新节点/链接后,需要再次调用force.start()以使其考虑到它们。

文档显示,您必须再次调用force.start()才能识别新节点。https://github.com/mbostock/d3/wiki/Force-Layout#wiki-start 这是不正确的吗? - Joe Wood
嗨,Lars - 这不是我看到的情况,如果没有添加 force.start(),D3 似乎会忽略新添加的节点。 - Joe Wood
抱歉,我的评论不够清晰 - 我的意思是你是正确的,确实需要调用 force.start()。我会更新答案。谢谢。 - Lars Kotthoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接