2012-03-01 16 views
17

新しいデータをバインドするだけで、いくつかのD3.js要素を更新する方法を検討しようとしています。私は実際にこれが可能かどうかはわかりませんが、そうすべきだと感じています。新しいデータをバインドして要素を操作する

だから最初に私は4つのSVGの円を作成し、データの関数としてオフセットcxを設定している:

<body><div id="container"></div></body> 

var svg = d3.select("div.container").append("svg") 
    .attr("class", "chart") 
    .attr("width", 1000) 
    .attr("height", 500); 

    // Create initial data and display 
    var data = [0, 10, 20, 30]; 
    var circle = svg.selectAll("circle") 
     .data(data) 
     .enter() 
     .append('circle') 
     .attr("cx", function(d) { 
     return d*10; 
     }) 
     .attr("cy", 100) 
     .attr("r", 10) 
     .style("fill", "steelblue"); 

次の私は、新しいデータやトランジションを添付します。私は円が新しい位置(それは私が達成しようとしているものです)に渡ってゆっくりと移動見ることを期待するが、彼らはそうではない。

var data1 = [40, 50, 60, 70]; 
    circle.data(data1).transition().duration(2500); 

アム私は基本的なエラーを作るの?おそらく私は間違った選択肢を持っています。あるいは単にデータを操作して要素を更新することはできませんか?

更新:私がconsole.log(circle)を実行すると、SVGサークル要素の配列が表示されますが、これは私が期待するものです。

答えて

23

D3.jsは、簡単な視覚化のために繰り返していることがあります。特定の方法でデータから派生した属性を持つ要素を作成し、その後それらの属性を新しいデータに変換したい場合は、値を導出する方法を再度指示する必要があります(必要な場合別のビジュアルレイアウトなど、別のことをする)。 @Andrewが言っているように、あなたはそれが移行するときに何をすべきかを教えなければならない。

あなたはこのパターンに従うことによって、この「問題」を回避することができます:2.0で

var foo = d3.select('foo'); 
function redraw(someArray){ 
    var items = foo.selectAll('bar').data(someArray); 
    items.enter().append('bar'); 
    items.exit().remove(); 
    items 
    .attr('foo',function(d){ return d }); 
} 

をするときにappend()新しい彼らは自動的に元のデータバインドの選択に追加されenter()内の項目、そうattr()への呼び出し後でこれに適用されることはありません。これにより、初期値の設定と値の更新の両方に同じコードを使用できます。

各アップデートのSVGラッパーを再作成したくないので、redraw機能の外でこれを作成する必要があります。

あなたがトランジションを実行したい場合は

:上記の仲間は、インデックスによるデータとオブジェクトという

function redraw(someArray){ 
    var items = foo.selectAll('bar').data(someArray); 
    items.enter().append('bar') 
    .attr('opacity',0) 
    .attr('foo',initialPreAnimationValue); 
    items.exit().transition().duration(500) 
    .attr('opacity',0) 
    .remove(); 
    items.transition.duration(500) 
    .attr('opacity',1) 
    .attr('foo',function(d){ return d }); 
} 

注意。仲介データポイントを削除して削除する前に、そのデータポイントを削除する前に(最後のアイテムを削除し、そのアイテムのように見えるように変更するのではなく)、関連付ける個別の(インデックス以外の)文字列値を指定する必要があります各項目はで:

var data = [ 
    {id:1, c:'red', x:150}, 
    {id:3, c:'#3cf', x:127}, 
    {id:2, c:'green', x:240}, 
    {id:4, c:'red', x:340} 
]; 
myItems.data(data,function(d){ return d.id; }); 

あなたはこの例を見ると、それはmy D3.js playgroundに住んで遊ぶことができます。

まず、データ行の1つをコメントアウトしてから、もう一度元に戻すとどうなるかを確認してください。次に、ƒ('id')を、行4のdata()への呼び出しから削除し、再度コメントアウトしてデータ行に入れます。

編集:別の方法として、輝かしいmbostockによってコメントとして、あなたのコード干上がるするための方法として、再利用可能な機能と一緒にselection.call()を使用することができます。上記のように

var foo = d3.select('foo'); 
function redraw(someArray){ 
    var items = foo.selectAll('bar').data(someArray); 
    items.enter().append('bar').call(setEmAll); 
    items.exit().remove(); 
    items.call(setEmAll); 
} 

function setEmAll(myItems){ 
    myItems 
    .attr('foo',function(d){ return d*2 }) 
    .attr('bar',function(d){ return Math.sqrt(d)+17 }); 
} 

を、.call()関数を呼び出します選択肢を引数として渡すので、複数の場所で選択して同じ設定を行うことができます。

+0

恐ろしい答え、ありがとう。私はまだこのようなもののほとんどに頭をつけようとしていますが、これは本当の助けになるでしょう! – Richard

+2

礼儀正しい答え。 [selection.call](https://github.com/mbostock/d3/wiki/Selections#wiki-call)と互換性のある方法で 'redraw'関数を書くこともできます。関連性:[再利用可能な図表へ](http://bost.ocks.org/mike/chart/)。 – mbostock

+1

@mbostockああ、それはとても役に立ちます。以前は '.call() 'を見たことがなかった。私はできるだけ早くD3.js初心者です。私はその情報を含めるように編集します(そしてすべての可能性を私の頭の中に試してみるためにドキュメントを完全に通過させます)。 – Phrogz

2

これでOK!

circle.data(data1).transition().duration(2500).attr("cx", function(d) { 
     return d*10; 
    }); 
2

既存の視覚化に新しいデータを追加するための非常に良いリソースは、データの更新に関する公式のチュートリアルです。

http://bl.ocks.org/mbostock/3808221

メインテイクアウトは、あなたがデータを呼び出すときD3は、データが古くなる対、データが新しいとなっているトラックを保つことができるように、キーの機能を定義したいということです。

関連する問題