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

Pep*_*G-a 3 d3.js force-layout

在带有强制模块的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
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经能够通过在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);
Run Code Online (Sandbox Code Playgroud)

虽然这是有效的,但它非常多余.有没有一种方法可以使用新参数刷新模拟?我尝试了以下但它不起作用

function connectedNodes() { 

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

//restart simulation with new parameters
simulation.restart();
}
Run Code Online (Sandbox Code Playgroud)

alt*_*lus 5

您需要引用要更新的力.这可以使用以下两种方式之一完成:

  1. 正如Cool Blue在他们的评论中指出的那样,你可以通过调用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)
      );
    
    Run Code Online (Sandbox Code Playgroud)

    稍后可以在需要时通过其名称获取力:

    var forceLink = simulation.force("link");  // Get the force by its name
    
    Run Code Online (Sandbox Code Playgroud)

    就个人而言,我喜欢这种方法,并且只要有可能,我会更喜欢它,因为我不喜欢有很多引用/变量.

  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
    
    Run Code Online (Sandbox Code Playgroud)

无论你选择哪种方式,你都可以通过做类似的事情来更新你的力量

linkDistance += 10;
forceLink.distance(linkDistance);
Run Code Online (Sandbox Code Playgroud)

这将在计算下一个滴答后将新值考虑在内.如果模拟已经停止或您只是想再次加热,您可以打电话

simulation.alpha(1).restart();
Run Code Online (Sandbox Code Playgroud)

我已经设置了一个示例,当您将鼠标悬停在SVG上时会显示这些实时更新.这将更新linkDistance并重新启动力布局.