【D3.js】データセットの増減をDOM要素に反映する
D3.jsでデータセットの増減をDOM要素に反映して更新する方法です。
初めは混乱しがちですか、いったん理解してしまえば非常に簡単でなおかつ強力な機能なので是非使いこなしたいですね。
準備
D3を用いて操作を行うドキュメントを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<html> <head> <script src="http://d3js.org/d3.v3.min.js"></script> <style> div { color: white; height:50; background-color:blue; } </style> </head> <body> <div>test1</div> <div>test2</div> <div>test3</div> <div>test4</div> </body> </html> |
データセットを束縛する
下記のデータセットをDIV要素に束縛します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var dataSet = [ {id:"A", val:100}, {id:"B", val:110}, {id:"C", val:120}, {id:"D", val:130}, {id:"E", val:140}, ] //データセットを束縛 d3.select('body').selectAll('div') .data(dataSet) .enter() .append('div') .style({ width:function(d){ return d.val+"px"} }) .text(function(d){ return d.id }); |
出力結果
選択したDIV要素の数が、データセットの数に対して足りていないので、D3によって新たなDIV要素が追加されました。
しかし、その後のstyle/textの適用は新たに追加された要素に対してしか行われていません。
これは意図した動作(選択した要素・新たに追加された要素ともにデータセットを元にした更新を行いたい)と違っています。
これらが正しく適用されるように、データセットの束縛と、要素の更新をわけます。
束縛後→要素の更新
1 2 3 4 5 6 7 8 9 10 11 12 |
//データセットを束縛 d3.select('body').selectAll('div') .data(dataSet) .enter() .append('div') //要素の更新 d3.selectAll('div') .style({ width:function(d){ return d.val+"px"} }) .text(function(d){ return d.id }); |
出力結果
選択したdiv要素にデータセットを束縛し、足りないdiv要素をappendします。
その後改めてdiv要素を選択し、データセットの内容を元にdiv要素の属性値を更新しています。
これで意図通り、指定したすべての要素がデータセットを元に更新されました。
次は、データセットの内容を変更して要素を更新してみます。
データセットの変更→要素の更新
1 2 3 4 5 6 7 8 9 10 |
var dataSet2 = [ {id:"A", val:100}, {id:"B", val:110}, {id:"D", val:130}, {id:"E", val:140}, ] d3.selectAll('div') .data(dataSet2) .style("background-color", "red"); |
データセットの数を減ら(Id:”C”のデータを削除)してDIV要素に束縛し、選択したDIV要素の背景色を「赤」に変更しています。
出力結果
新たなデータセットの内容が束縛され要素が更新されました。
しかし、以前束縛されていたデータセットの内容とはまったく関係なく、単に上の要素から順に新たなデータセットが束縛されて要素の更新がおこなわれています。
以前のデータセットと新しいデータセットの差分を要素に反映するには、dataメソッドのコールバックを使用します。
dataメソッドのコールバック
1 2 3 4 5 6 7 8 9 10 11 |
var dataSet2 = [ {id:"A", val:100}, {id:"B", val:110}, {id:"D", val:130}, {id:"E", val:140}, ] d3.selectAll('div') .data(dataSet2, function(d){ return d.id }) .style("background-color", "red"); |
上記では、データセットのid値を元に新たなデータセットを要素に束縛します。
出力結果
削除されたid:”C”のデータが束縛されていた要素を除いて、正しく更新がおこなわれました。
このようにdataメソッドのコールバックを使用することで、データセットの増減を要素に正しく反映することができます。
不要になった要素の削除
1 2 3 4 5 |
d3.selectAll('div') .data(dataSet2, function(d){ return d.id }) .style("background-color", "red") .exit() .remove(); |
出力結果
最後にexit/removeメソッドを用いて不要となった要素を削除しました。
総括
データセットの増減に合わせてDOM要素を操作するには、多少コツがいります。
しかし、動的なビジュアライゼーションを作成するには必要不可欠な知識となるので、是非いろいろ弄って理解を深めてみてください。
transition効果をかけてみたり、途中のexitメソッドを省いたらどうなるのか? など試してみると面白いかもしれません。