4

D3 で強制レイアウト シミュレーションを d3.layout.force()....start() すると、アクティブなイベントも継続します。

5 秒のタイムアウトを設定して、グラフ フォース レイアウト シミュレーションが形成されて停止するようにします (.stop() または alpha(0) を呼び出します)。これは停止するように機能しますが、ノードをドラッグするとすぐにシミュレーションが再開されます。

次のコードもjsfiddleから簡単にテストでき、最後の行stop()が発行され、シミュレーションがすぐに停止することを示していますが、ノードをドラッグするとすぐにシミュレーションが再開されます。これは強制ドラッグでハードコーディングされていると思います。これを無効/登録解除する方法はありますか?

var svgContainer = d3.select("#svgContainer");

var element0a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,100)");
var element0b = element0a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","red");

var element1a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,200)");
var element1b = element1a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","green");

var element2a = svgContainer.append("g").attr("class","node").attr("transform","translate(100,300)");
var element2b = element2a.append("rect").attr("x",0).attr("y",0).attr("width",20).attr("height",10).attr("fill","blue");

var nodeArray = new Array();
nodeArray[0] = { id : "000", label : "label 000", ui : element0a };
nodeArray[1] = { id : "001", label : "label 001", ui : element1a };
nodeArray[2] = { id : "002", label : "label 002", ui : element2a };

var linkArray = new Array();

var force = self.force = d3.layout.force()
    .nodes(nodeArray)
    .links(linkArray)
    .gravity(.05)
    .distance(80)
    .charge(-100)
    .size([600, 600])
    .start();

var node = svgContainer.selectAll("g.node")
    .data(nodeArray)
    .call(force.drag);


force.on("tick", function() {
      node.attr("transform", function(d) {return "translate(" + d.x + "," + d.y + ")";});
    });

// HERE !!!! Without the stop() the simulation goes fine. With the stop() the simulation will immediately stop, but will continue as soon as you drap something. I want the simulation to never start again. 

force.stop();

これは例のスクリーンショットです:

ここに画像の説明を入力

4

2 に答える 2

10

ノードが内部でドラッグされたときに呼び出される関数で、シミュレーションが再開されます。ただし、この動作は上書きできます。イベント名は「drag.force」で、 からアクセスできますforce.drag。通常の動作の代わりに、次のようにシミュレーションを再開せずに座標を直接変更できます。

var node...
  .call(force.drag().on("drag.force", function() {
    d3.select(this).attr("transform", "translate(" + d3.event.x + "," + d3.event.y + ")");
  }));

これは、通常のドラッグ動作に対応します。これを行う前に、シミュレーションを停止して、ドラッグ イベントと強制ティックが干渉しないようにすることをお勧めします。force.stop()変更したイベント ハンドラーの先頭で呼び出すだけです。

最後に、ドラッグ イベントの起点をリセットする必要があります。そうしないと、ドラッグされた要素を再びドラッグすると、元の位置に「ジャンプ」して戻ることに気付くでしょう。これは、イベント ハンドラーの変更と同様の方法で行われます。現在の変換を取得し、期待される形式で座標を返すだけです。

var node...
  .call(force.drag().origin(function() {
    var t = d3.transform(d3.select(this).attr("transform")).translate;
    return {x: t[0], y: t[1]};
  }));

完全なコードは、更新された jsfiddle hereにあります。

于 2013-04-19T20:50:34.780 に答える
1

適切な「摩擦」を設定すると、停止する必要がある時間を制御することはできませんが、それを行う必要があります。

var force = self.force = d3.layout.force()
  .nodes(nodeArray)
  .links(linkArray)
  .gravity(.05)
  .distance(80)
  .charge(-100)
  .friction(0.5)
  .size([600, 600])
  .start();
于 2013-04-19T20:15:47.020 に答える