2016-10-04 71 views
3

我試圖將節點逐個添加到d3力仿真(在版本4中!),但有些仿真似乎並沒有在仿真後被仿真演變。d3 v4力量作用於動態添加的節點


目前模擬分配一個節點,那麼一個功能,ADDNODE被調用兩次增加兩個節點。每個都被添加到模擬中,有一個圓和一條線被渲染,並且有一個光標事件被逐個添加。

(技術上與第一和第二節點在同一時間內完成,如在第一僅設置當ADDNODE被稱爲第二)

然後,被點擊的節點時,一個新的節點,連接到光標下的那個,應該被創建。然後這個節點應該像其他任何模擬一樣在仿真的力量下進化。


然而,而一個或兩個節點似乎要創建精細,後來節點似乎並不模擬下有所發展。具體來說,應該在節點之間保持一定空間的多體力似乎不起作用。


我的直覺是,被在不合適的時間模擬的勾選功能添加的節點(早期問題解決了通過添加一些simulation.stop和simulation.restart命令正在添加新節點的任何時間),但在理論上,每當添加新的物體時,應該暫停模擬。

這是在d3 v4中動態添加節點的正確實現,還是強制突出顯示破壞方法的問題? This以前的答案幫助我意識到我需要合併新的條目,但部隊似乎在那裏工作得很好。

var w = 250; 
 
var h = 250; 
 

 
var svg = d3.select("body").append("svg"); 
 

 
svg.attr('width', w) 
 
    .attr('height', h); 
 

 
// ensures links sit beneath nodes 
 
svg.append("g").attr("id", "lnks") 
 
svg.append("g").attr("id", "nds") 
 

 
function new_node(id) { 
 
    this.id = id; 
 
    this.x = w/2; 
 
    this.y = h/2; 
 
} 
 

 
function new_link(source, target) { 
 
    this.source = source; 
 
    this.target = target; 
 
} 
 

 
var nodes = []; 
 
var links = []; 
 

 
var node; 
 

 
var circles; 
 

 
var link; 
 

 
var simulation = d3.forceSimulation() 
 
    .force("link", d3.forceLink().distance(80).id(function(d) { 
 
    return d.id; 
 
    })) 
 
    .force("charge", d3.forceManyBody().strength(-1000)) 
 
    .force("xPos", d3.forceX(w/2)) 
 
    .force("yPos", d3.forceY(h/2)) 
 
    .on('tick', ticked); 
 

 
simulation.stop(); 
 

 
var newNode = new new_node(0); 
 
nodes.push(newNode); 
 

 
for (var i = 1; i < 3; i++) { 
 
    if (i == 3) continue; 
 
    addNode(0, i) 
 
} 
 

 
function addNode(rootId, newId) { 
 

 
    var newNode = new new_node(newId); 
 
    nodes.push(newNode); 
 
    var newLink = new new_link(rootId, newId); 
 
    links.push(newLink); 
 

 
    //adds newest link and draws it 
 
    link = svg.select("#lnks").selectAll(".link") 
 
    .data(links) 
 
    var linkEnter = link 
 
    .enter().append("line") 
 
    .attr("class", "link"); 
 
    link = linkEnter.merge(link); 
 

 
    //adds newest node 
 
    node = svg.select("#nds").selectAll(".node") 
 
    .data(nodes) 
 
    var nodeEnter = node 
 
    .enter().append("g") 
 
    .attr("class", "node"); 
 

 
    //draws circle on newest node 
 
    var circlesEnter = nodeEnter.append('circle') 
 

 
    node = nodeEnter.merge(node); 
 
    circles = d3.selectAll('circle'); 
 

 
    simulation.stop(); 
 

 
    simulation.nodes(nodes); 
 

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

 
    restartSim(); 
 
} 
 

 
//starts up the simulation and sets up the way the leaves react to interaction 
 
function restartSim() { 
 
    simulation.restart(); 
 

 
    circles.on('click', function(d, i) { 
 
    addNode(i, nodes.length) 
 
    }) 
 
} 
 

 
function ticked() { 
 
    link 
 
    .attr("x1", function(d) { 
 
     return d.source.x; 
 
    }) 
 
    .attr("y1", function(d) { 
 
     return d.source.y; 
 
    }) 
 
    .attr("x2", function(d) { 
 
     return d.target.x; 
 
    }) 
 
    .attr("y2", function(d) { 
 
     return d.target.y; 
 
    }); 
 

 
    node.attr("transform", function(d) { 
 
    return "translate(" + d.x + "," + d.y + ")"; 
 
    }); 
 
}
.link { 
 
    stroke: #bbb; 
 
} 
 
.node circle { 
 
    pointer-events: all; 
 
    fill: black; 
 
    stroke-width: 0px; 
 
    r: 20px 
 
} 
 
h1 { 
 
    color: white; 
 
}
<script src="https://d3js.org/d3.v4.min.js"></script>

代碼也放在這裏codepen: http://codepen.io/zpenoyre/pen/kkxBRW?editors=0010

回答

4

力模擬顧名思義是彼此相互作用的粒子模擬。阿爾法被用來通過在每次迭代時衰減來幫助收斂系統。這些力被乘以alpha,所以在每次迭代時力會變得更弱,直到模擬停止時alpha達到非常低的值。從D3文檔:

simulation.restart()<>

重新啓動模擬的內部定時器,並返回模擬。 結合simulation.alphaTarget或simulation.alpha,此方法可用於在交互期間「模擬」模擬,例如拖動節點時的模擬,或暫時使用simulation.stop暫停模擬時恢復模擬。

當你添加一個節點時,模擬已經停止,所以你需要用alpha1來「模擬」模擬。

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

    simulation.alpha(1); // <---- reheat; 

    restartSim(); 

這裏是更新的代碼筆: http://codepen.io/anon/pen/amqrWq?editors=0010

+0

那偉大工程,三江源。有沒有一種簡單的方法來理解alpha在這裏做什麼? 「再加熱」對我來說看起來並不是很直觀,[d3 API](https://github.com/d3/d3-force/blob/master/README.md#simulation_alpha)對我來說沒有多大意義就此主題而言。 – Zephyr

+0

真棒,我沒有意識到模擬有效,但仔細觀察,我很清楚地看到它。有意義的是,您希望減少模擬計算,但每次更改設置時都需要重新啓動它。謝謝! – Zephyr

+0

@Zephyr從你的第二個評論中,你可能會得到它。但是在'simulation.alphaTarget'提交中,您或其他任何人都可以獲得很好的附加信息:(https://github.com/d3/d3-force/commit/8a2c8590bb879c70eb2e10264b41d0200c887be9​​)「這樣可以設置」desired「alpha模擬,並使模擬平滑地內插到期望的值,默認情況下,目標值爲零,以便模擬冷卻,但通過將其設置爲 非零值,例如在拖動交互期間,你也可以用它來模擬熱量。「 – ibgib