LoginSignup
9
9

More than 5 years have passed since last update.

d3.selection について

Last updated at Posted at 2012-10-08

d3enter() などの意味や selection の中身がよくわからなかったので調べてみました。それにしても d3 のドキュメントの充実っぷりは半端ないですね。

selection とは

d3 の全ての基本が d3.selection です。基本的には DOM 要素の入った配列(の入った配列)ですが、data(), append() などのメソッド(d3 では operator と呼ばれている)がついており、DOM 要素に対していろいろな操作をすることができます。

<body>
  <p>Hello, World!</p>
  <p>Hello, World!</p>
  <p>Hello, World!</p>
</body>
var p = d3.select('body').selectAll('p');

console.log(p instanceof d3.selection);
// true

for (var k in p) if (p.hasOwnProperty(k)) {
  console.log(k);
}
// 0

for (var k in p[0]) if (p[0].hasOwnProperty(k)) {
  console.log(k, p[0][k]);
}
// 0 <p>​Hello, World!​</p>​
// 1 <p​​​>​Hello, World!​</p>​
// 2 <p​​​>​Hello, World!​</p>​
// parentNode <body>​…​</body>​

selection のネスト

selectAll() を一回呼んだだけだと、なぜか一個だけ配列の入った配列です。入れ子状の DOM に対して selectAll() を二度呼ぶと一階層繰り上がり、一番上の配列の要素が複数になります。

<table>
  <tr><th>Wow</th><td>Hello</td></tr>
  <tr><th>Wow</th><td>Hello</td></tr>
  <tr><th>Wow</th><td>Hello</td></tr>
</table>
console.log(d3.selectAll('tr'));
// [Array[3]]

console.log(d3.selectAll('tr').selectAll('td'));
// [Array[1], Array[1], Array[1]]

参考 Nested Selections

data() と selection join

data() を使うと selection にデータを関連づけることができます。具体的には、各 DOM 要素に __data__ プロパティが設定されます。また、その際 selection から update, enter, exit という三種類の subselection(?)が生まれます。

  • update selection は、要素とデータ両方揃った分の配列。data() の返り値はこれです。要素を更新するのに使います。 enter()exit() メソッドがついており、それぞれ下の二つを返します。
  • enter selection は、要素よりもデータの方が多かった場合に余った分のデータ(を格納したオブジェクト)の入った配列。要素を新しく追加するのに使います。
  • exit selection は、データよりも要素の方が多かった場合に余った分の要素の入った配列。不要になった要素を削除するのに使います。
var updating = d3.select('body').selectAll('p')
  .data([4, 8, 15, 16, 23, 42]);

console.log(updating instanceof d3.selection);
// true

for (var k in updating) if (updating.hasOwnProperty(k)) {
  console.log(k);
}
// -> 0
// -> enter
// -> exit

for (var k in updating[0]) if (updating[0].hasOwnProperty(k)) {
  console.log(k, updated[0][k]);
}
// 0 <p>​Hello, World!​</p>​
// 1 <p​​​>​Hello, World!​</p>​
// 2 <p​​​>​Hello, World!​</p>​
// 3 null
// 4 null
// 5 null
// parentNode <body>​…​</body>​

enter selection はこんな感じです。

var entering = updating.enter();

console.log(entering instanceof d3.selection);
// false

for (var k in entering) if (entering.hasOwnProperty(k)) {
  console.log(k);
}
// 0

for (var k in entering[0]) if (entering[0].hasOwnProperty(k)) {
  console.log(k, entering[0][k]);
}
// 0 null
// 1 null
// 2 null
// 3 Object
// 4 Object
// 5 Object
// update [<p>​Hello, World!​</p>​, <p>​Hello, World!​</p>​, <p​>​Hello, World!​</p>​, null, null, null]
// parentNode <body screen_capture_injected=​"true">​…​</body>​

なお entering[0][3,4,5] に入っている Object__data__ プロパティにデータを格納しています。

exit selection は enter selection と同じような感じなので省略します。

一見面倒な仕組みですが、大きなメリットがあります。

  • 変更がある度に全てを書き換えるのではなく、必要な分だけ書き換えるので、パフォーマンスの向上が期待できる
  • 要素の追加や削除にアニメーションをつけられる

参考
Thinking with Joins

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9