2013-02-10 13 views
10

d3のパックレイアウト(http://bl.ocks.org/4063530)の周りに私の心を包み込みたいと思っています。d3.jsのlayout.packを更新する

私は基本的なレイアウトが動作していますが、私は新しいデータでそれを更新したいと思います。新しいデータを収集し、それを現在のレイアウトパックにバインドし、それに応じて更新する(更新/終了/入力)。

私の試みはここ(http://jsfiddle.net/emepyc/n4xk8/14/)です:私は、データをバインドするにはどうすればよい

var bPack = function(vis) { 
    var pack = d3.layout.pack() 
    .size([400,400]) 
    .value(function(d) {return d.time}); 

    var node = vis.data([data]) 
    .selectAll("g.node") 
    .data(pack.nodes) 
    .enter() 
    .append("g") 
    .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

node.append("circle") 
    .attr("r", function(d) { return d.r }); 

    node.filter(function(d) { return !d.children; }).append("text") 
    .attr("text-anchor", "middle") 
    .attr("dy", ".3em") 
    .text(function(d) { return d.analysis_id }); 

    bPack.update = function(new_data) { 
     console.log("UPDATE"); 

     node 
     .data([new_data]) 
     .selectAll("g.node") 
     .data(pack.nodes); 

     node 
     .transition() 
     .duration(1000) 
     .attr("class", function(d) { return d.children ? "node" : "leaf node" }) 
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" }); 

     node.selectAll("circle") 
     .data(new_data) 
     .transition() 
    .duration(1000) 
    .attr("r", function(d) { return d.r; }); 

    }; 

具体的な質問...

? (データは複雑な構造ではなく、データの配列ではないため)

新しいノード/リーフをレイアウトに追加するにはどうすればよいですか?そして古いものは取り除かれましたか?

実例へのポインタは非常に高く評価されます。関連性の

+0

質問をしてからしばらく時間がかかっていますが、おそらく私の解決策をチェックできますか?私はあなたのジレンマに正しい答えがあるのか​​不思議です。そして、おそらく他の人はあなたの質問がどのように解決されたのか興味があります。:) – VividD

+0

はい、答えはパックレイアウトがあなたのためにすべての仕事をさせることです。この作業を開始したときはこれは明白ではありませんでしたが、別の例(ツリーレイアウトの更新)でこのソリューションが機能していました。実際の例をありがとう。 – emepyc

+0

問題を解決できたことをうれしく思います。最終的な解決策はシンプルですが、最初に問題に取り組む際には明らかではありません。私はそのような場合が大好きです。 – VividD

答えて

10

実行例はhereです。

基本的に、最初の場所にすべての円、ツールチップなどが作成され、配置される初期ロードのコードがあります。同様に、レイアウト(パック)も作成されます。

ボタンを押すたびに、新しいデータがパックにロードされ、パックが再計算されます。その重要なコードはここにある:ここで

あなたは今パックレイアウトにデータ(負荷)をバインドします(私の例では、そのランダムデータは、もちろんあなたはJSONまたはコードまたは類似からデータを持っています):

pack.value(function(d) { return 1 + 
      Math.floor(Math.random()*501); }); 

ここで新しいレイアウトが計算されます。その後

pack.nodes(data); 

を、要素が新しい位置に移行され、そしてあなたが決めるように、その属性が変更されます。

私は入力/更新/終了のパターンや変換(他のソリューションで見られるかもしれない)を使用しないことを強調したいと思います。ここで

は、アクションの遷移を持ついくつかの写真です:

スタート:

start

変遷:

transition

終了:

end

+0

'enter()'/'exit()'メソッドを使用しないことについての注意点で述べた複雑さに苦しんでいます。私はこれを働かせようとしており、追加された複雑さのニュアンスについて少し説明できるかどうか疑問に思っています。ここであなたの例を非常に感謝します! – Brian

+0

これがD3 v4で可能かどうか知っていますか?私は同じ機能が表示されません。 – gwg

+0

@gwg残念ながら私は考えていません。おそらく私は何かを試してみるだろうが、正直言って私は今、そして近い将来、時間がない。 D3 v3とD3 v4の違いが分かっています。 Murphy Lawによれば、これは動作せず、D3 v4では不可能であり、将来のD3バージョンでは決して可能ではありません。しかし、私が関連して有用なものを見つけたらお知らせします。 – VividD

3

、あなたはまだ見直されていない場合:
http://bl.ocks.org/3808218 - 一般的な更新パターン、I
http://bl.ocks.org/3808221 - 一般的な更新パターン、II
http://bl.ocks.org/3808234 - 一般的な更新パターン、III

このサンプルフィドルはありませんがありますしかし、ここではデータを更新するための少なくとも1つのアプローチがあります。

http://jsfiddle.net/jmKH6/

// VISUALIZATION 
var svg = d3.select("#kk") 
    .append("svg") 
    .attr("width", 500) 
    .attr("height", 600) 
    .attr("class", "pack"); 

var g = svg.append("g") 
    .attr("transform", "translate(2,2)"); 

var pack = d3.layout.pack() 
     .size([400,400]) 
     .value(function(d) {return d.time}); 

function update(data) { 

    var nodeStringLenth = d3.selectAll("g.node").toString().length; 
    if (nodeStringLenth > 0) { 
     d3.selectAll("g.node") 
      .remove(); 
    } 

    var node = g.data([data]).selectAll("g.node") 
      .data(pack.nodes); 

     node.enter() 
      .append("g") 
      .attr("class", function(d) { return d.children ? "node" : "leaf node"; }) 
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

     node.append("circle") 
      .attr("r", function(d) { return d.r }); 

     node.filter(function(d) { return !d.children; }).append("text") 
      .attr("text-anchor", "middle") 
      .attr("dy", ".3em") 
      .text(function(d) { return d.analysis_id }); 

     node 
      .exit() 
      .remove(); 
} 


var myData = [data1, data2, data3]; 
update(data1); 
setInterval(function() { 
    update(myData[Math.floor(Math.random() * myData.length)]); // http://stackoverflow.com/questions/4550505/getting-random-value-from-an-array?lq=1 
}, 1500); 
+4

コメントありがとうございます。あなたがここでやっていることは、すべてのノードを削除し、私が望むものではなく、すべての更新で新しいノードを構築することです。私はデータをバインドしてトランジションを使うことに興味があります(または、バインドせずに新しい値/ノードでノードを「適切な位置に」変更する必要がありますか?)。 – emepyc

4

私は最近、同じ問題を抱えていた、とだけでなく一般的な更新パターンのチュートリアルに出くわしました。これらは私の目的に役立たなかった。グラフに数百のDOM要素(ForceLayout)があり、個々のノードごとにプロパティを持つRESTデータを受け取っていました。あなたがmg1075の提案に応じて言ったように、データを再バインドしてリフレッシュするとグラフ全体が再構築されました。私の場合、DOMの更新を完了するのに数分かかりました。

後で更新が必要な要素に一意のIDを割り当てることになってしまい、JQueryでピッキングしました。私のグラフ設定全体はD3を使用していますが、私のアップデートはそうではありません。これは悪いと感じますが、うまくいきます。私のDOMの大部分を破壊して再作成することから数分を取るのではなく、3秒(REST呼び出しのタイミングを外した)のようなものが必要です。私は、D3でプロパティ更新のようなものを実現できないという理由は見当たりません。

おそらく、Mike Bostockがremove()または適切なsubselection関数をenter()選択に追加した場合、純粋なD3パターンに従って更新を行うことができます。これを解明しながら、私はデータのサブセットをバインドしようとしていましたが、新しいプロパティを追加したデータを追加し、更新が必要な要素を取得するためにサブ選択しましたが、機能しませんでした。 ()選択。

+0

マイクは、グラフをパッキングする円の中の異なるデータ間をトランジションするための透明で簡単な方法を追加するべきだと思います。私はドリルダウン(円をダブルクリックして "ダイビング")する必要があるグラフを持っており、サーバから一度に1レベルしか取得しないので、サーバからそのレベルのデータを要求し、私はきれいにアニメーションをドリルダウンしたいです。 – vsync

関連する問題