2016-10-04 22 views
3

ノードをd3 forceシミュレーション(バージョン4では!)に1つずつ追加しようとしていますが、作成された後にシミュレーションによって進化していないように見えるもの。d3 v4動的に追加されたノードに作用する力


現在シミュレーションは、その後、1つのノードの機能を割り当てて、てaddNodeを二回、さらに2つのノードを追加すると呼ばれています。それぞれがシミュレーションに追加され、円と線が描画され、カーソルイベントが1つずつ追加されます。

ノードがクリックされたとき、

次に、新しいノードを、(技術的に第一及び第二のノードは最初のみにaddNode第二に呼び出されたときに設定されているように、同時に行われる)接続しますカーソルの下のものまで、作成する必要があります。このノードは、他のシミュレーションのようにシミュレーションの力の下で進化するはずです。


しかし、 1ながらまたは2つのノードが、後にノードがシミュレーションの下で進化していないようです、罰金を作成しているように見えます。具体的には、ノード間にある程度のスペースを確保する必要のある多体力は機能していないようです。


私の直感は、(以前の問題がいくつか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は、反復ごとに減衰することによってシステムを収束させるのに役立ちます。力はアルファによって掛け合わされるので、各反復において、アルファが非常に低い値に達するまで力が弱くなります。 D3のドキュメントから:>

simulation.restart()<

は、シミュレーションの内部タイマを再起動し、シミュレーションを返します。 simulation.alphaTargetまたはsimulation.alphaと組み合わせて、この メソッドを使用して、ノードのドラッグ時と同様に などの対話中にシミュレーションを「再加熱」するか、シミュレーション後に一時的にシミュレーションを再開する シミュレーションを使用してシミュレーションを一時停止します。

ノードを追加するとシミュレーションが既に停止しているため、シミュレーションをアルファ1で「再加熱」する必要があります。、ありがとうの素晴らしい作品 http://codepen.io/anon/pen/amqrWq?editors=0010

+0

:ここ

simulation.force("link") .links(links); simulation.alpha(1); // <---- reheat; restartSim(); 

は、更新されたコードペンです。ここでアルファが何をしているのかを理解する簡単な方法はありますか? 「Reheating」は私には直感的ではないようで、[d3 API](https://github.com/d3/d3-force/blob/master/README.md#simulation_alpha)は私にとっては意味がない件名に。 – Zephyr

+0

驚くべきことに、シミュレーションを効果的に行うことはできませんでしたが、よく見ています。シミュレーションの計算量を減らしたいが、セットアップを変更するたびにシミュレーションを再開する必要があります。ありがとう! – Zephyr

+0

@Zephyr 2番目のコメントから、おそらくそれが得られます。しかし、あなたや他の誰かのために 'simulation.alphaTarget'コミットのための良い追加情報があります:(https://github.com/d3/d3-force/commit/8a2c8590bb879c70eb2e10264b41d0200c887be9​​)"これはシミュレーションでは、 シミュレーションをスムーズに目的の値に向かって補間します。デフォルトでは、 の目標値は0で、シミュレーションが冷たくなりますが、 に設定することで、ドラッグ操作の間など、それを使用して シミュレーションヒートを得ることもできます。 – ibgib

関連する問題