D3-初始化图形后强制更新参数

D3-Force updating parameters after initializing graph

在带有 force 模块的 D3 v4 中,如何在初始化图形后更新模拟参数?

更准确地说,我试图在用户单击其中一个节点时更改力导向图的 .forceLink.forceManyBody

 var node = svg
    .append("g")
    .attr("class", "gnodes")
    .selectAll(".node")
    .data(graph.nodes)
    .enter()
    .append("g")
    .attr("class", "node")
    .on('dblclick', connectedNodes); //calls for change in simulation parameters

到目前为止,我已经能够通过在 connectedNodes 函数下复制模拟来更新它:

function connectedNodes() {

//new parameters
linkDistance = 5;
fCharge = -10;

//replicates the initial simulation code
simulation = d3.forceSimulation()
    .force("link", d3.forceLink()
        .id(function(d) {return d.id;})
        .distance(linkDistance)
        )
    .force("collide", d3.forceCollide()
        .radius(function(d){return d.r + 10})
        .strength(1)
        )
    .force("charge", d3.forceManyBody()
        .strength(fCharge)
        )
    .force("center", d3.forceCenter(width / 2, height / 2));

simulation.nodes(graph.nodes).on("tick", ticked);

simulation.force("link").links(graph.links);

虽然这可行,但它非常多余。有没有一种方法可以用新参数刷新模拟?我已经尝试了以下但它不起作用

function connectedNodes() { 

//new parameters
linkDistance = 5;
fCharge = -10;

//restart simulation with new parameters
simulation.restart();
}

您需要参考您要更新的部队。这可以使用以下两种方式之一完成:

  1. 正如 Cool Blue in their , you can easily get a reference to the force by calling simulation.force() 指出的那样,首先只传递了它注册的部队的名称。据推测,如果我们在传递一个匿名的就地力时创建了我们的模拟,就像这样:

    var simulation = d3.forceSimulation()
      .force("link", d3.forceLink()            // "link" is the name to register the force
        .id(function(d) { return d.id; })
        .distance(linkDistance)
      );
    

    以后需要的时候可以通过名字获取力:

    var forceLink = simulation.force("link");  // Get the force by its name
    

    就我个人而言,我喜欢这种方法,并且如果可能的话,我更喜欢它而不是第二种方法,因为我不喜欢周围有很多引用/变量。

  2. 创建时保留对力的引用。

    var forceLink = d3.forceLink()      // Keep a reference to the force
      .id(function(d) { return d.id; })
      .distance(linkDistance);
    
    var simulation = d3.forceSimulation()
      .force("link", forceLink )        // Pass the reference when creating the simulation
    

无论您选择哪种方式,您都可以通过执行类似

的操作来更新您的力量
linkDistance += 10;
forceLink.distance(linkDistance);

这将在计算下一个订单号时考虑新值。如果模拟已经停止或者你只是想再次加热你可以调用

simulation.alpha(1).restart();

我已经设置了一个 example,它会在您将鼠标悬停在 SVG 上时显示这些实时更新。这将更新 linkDistance 并重新启动强制布局。