2016-08-17 120 views
3

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

更准确地说,当用户点击其中一个节点时,我试图改变强制有向图的.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(); 
} 
+0

任何对此感兴趣的人都应该看到这个令人敬畏的演示,它完成了所有图形力变量:https://bl.ocks.org/steveharoz/8c3e2524079a8c440df60c1ab72b5d03 –

回答

5

您需要对要更新的力的引用。这是可以做到用以下两种方式:

  1. 在他们的comment指出的Cool Blue,你可以很容易地通过调用simulation.force()传递它注册的力量只是名字获得给力的引用首先。如果我们有,据说,创造我们的模拟,同时传递一个匿名的,就地力,像这样:个人

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

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

    后来的力可以通过它的名字在需要时获得,我喜欢这种方法,只要可能,我会喜欢第二种,因为我不喜欢有很多引用/变量。

  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并重新启动强制布局。

+0

我在更新forcecollide函数时遇到问题。图形首先被初始化,然后在用户点击时改变。在此更改过程中,某些节点的大小会根据您的建议而被修改。除了没有更新的forceCollide以考虑新的半径,所有的力都可以工作。我正在编辑问题以包含一些代码。 –

+1

@ PepeG-a这是一个自己的问题。请不要在你的问题中编辑它,因为它只会让读者感到困惑。而是发布一个新的,并在其中添加一个参考。一旦你发布它,我将会研究它。 – altocumulus

+0

当然,会做@altocumulus –