d3を学ぶ上で一番難しいのはenter、update、exitの関係でしょう。この中で、updateは特に明示するわけではないのも混乱の元です。
このページでは、復習も兼ねてそれぞれの役割を確認してみます。
まずは、datasetの要素数に合わせてdivとテキストを作成するサンプルから始めます。
enterとupdate
すでに、追加と削除ボタンが付いているのでこれを利用して、まずは新しくdatasetの要素数を増やしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //クリックするとdatasetを更新して要素数を7にする//////////////////// d3.select(".add") .on("click", function() { //datasetの新しい値 dataset = [ 5, 10, 15, 20, 25, 30, 35 ]; var divs = body.selectAll("div") //divのDOM要素が7になるように選択し直す。 .data(dataset); //データの要素数をカウントし抽出。updateセレクションに入る //enterセレクション。DOM要素がデータの要素数より少ない場合は新しく空のDOM要素を作る。 divs.enter() .append("div") //新しく作ったDOM要素にdivを追加。 .text(function(d){ //divの中にテキストを追加。 return "新しい数値は" + d + "になります"; }) .style("color", "blue"); //全てのp要素に適用 }); |
このコードのポイントは、.data(dataset)以降です。
まず、データの要素数をカウントし抽出します。
1 | .data(dataset) |
次に、.enter()で、DOM要素がデータの要素数より少ない場合は新しく空のDOM要素を作ります。
1 | .enter() |
新しく作ったDOM要素にdivを追加します。
1 | .append("div") |
新しく作ったdivにテキストを追加します。
1 2 3 | .text(function(d){ //<p></p>の中にテキストを追加。 return "新しい数値は" + d + "になります"; }) |
最後に、新しく作ったdivの色(テキストの色)を赤にします。
1 | .style("color", "blue"); //全てのp要素に適用 |
「追加」をクリックしてみると、新しく追加された要素だけが青になります。これは、enter()によって行われる更新は、新しいdiv要素にのみ適用されるからです。
全て更新したい場合はどうすればいいでしょうか。答えは簡単で、もう一度全てのdivを選択し直して、更新します。ここではupdateというコードは出てきませんが、実際にはupdate()を実行しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var divs = body.selectAll("div") //divのDOM要素が7になるように選択し直す。 .data(dataset) //データの要素数をカウントし抽出。updateセレクションに入る //enterセレクション。DOM要素がデータの要素数より少ない場合は新しく空のDOM要素を作る。 divs.enter() .append("div") //新しく作ったDOM要素にdivを追加。 .text(function(d){ //divの中にテキストを追加。 return "新しい数値は" + d + "になります"; }) .style("color", "blue"); //全てのp要素に適用 //update divs.style("color", "blue"); |
全て青に変更できました。
merge(結合)
実は、新しく増えたdivと既存のdivの更新はもっと短いコードで同時に行うことができます。merge()(結合という意味の英語)を使います。
1 2 3 4 5 6 7 8 9 10 11 | var divs = body.selectAll("div") //divのDOM要素が7になるように選択し直す。 .data(dataset) //データの要素数をカウントし抽出。updateセレクションに入る //enterセレクション。DOM要素がデータの要素数より少ない場合は新しく空のDOM要素を作る。 divs.enter() .append("div") //新しく作ったDOM要素にdivを追加。 .text(function(d){ //divの中にテキストを追加。 return "新しい数値は" + d + "になります"; }) .merge(divs) //既存のdiv要素も一緒に選択する .style("color", "blue"); //全てのp要素に適用 |
同じ結果になります。
exit
次に、datasetの要素が減った時の動作をexit()で操作してみましょう。以下のコードを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 | //クリックするとdatasetを更新して要素数を4にする//////////////////// d3.select(".remove") .on("click", function() { //datasetの新しい値 dataset = [ 5, 10, 15, 20 ]; body.selectAll("div") .data(dataset) //データの要素数をカウントし抽出 .exit() .style("color", "red"); //exit()のp要素に適用 }); |
ここでは、datasetの要素が4個に減っているので、「追加」によって増えた7個から3個減っています。exitによって、データがなくなってしまったdiv要素を選択し、style()で赤に変更しています。
一般的には余分なdiv要素は削除するので、remove()しましょう。
1 2 3 4 5 | body.selectAll("div") .data(dataset) //データの要素数をカウントし抽出 .exit() //.style("color", "red"); //exit()のp要素に適用 .remove(); |
まとめ
よって、enter, update, exitの関係は以下になります。
enter : データセットに追加され、まだDOM要素になっていないもの
update : すでにDOM要素になっている既存のデータ
exit : DOM要素として描画されていて、データセットから削除されたもの
この関係性を忘れないようにしましょう。