こちらのサイト「d3-selection」を参考に、要素の選択・変更・結合についてまとめました。
※ 随時更新
目次
1.selectionとは?
selectionは、属性・スタイル・プロパティ・HTMLまたはテキストなどを選択し、データに対応する要素を追加・削除またはプロパティ値を設定することができます。
例えば、全ての段落要素(p)にフォント色を設定する場合、次のようにします。
1 2 |
d3.selectAll("p") .style("color", “white”); |
d3.selectAll(“p”)
全ての段落要素を選択します。
.style(“color”, “white”);
選択した要素の文字色を白に設定します。
2.要素を選択するメソッド一覧
2−1.d3.select(selector)
引数で指定したセレクタ文字列に一致する最初の要素を選択します。
要素はドキュメント(HTML)の上から下の順に選択されます。
一致する要素がない場合は空の選択を返します。
ドキュメント内の最初の段落要素を選択するには次のようにします。
1 |
d3.select("p") |
また、文字列ではなく this のようにすると選択中のノードを意味します。
例えば、選択した段落要素のみスタイルを変更するには、次のようにします。
1 2 3 4 5 |
d3.selectAll("p").on("click", function() { d3.select(this) .attr("class", "bar") .style("color", "white"); }); |
2−2.d3.selectAll(selector)
引数で指定されたセレクタ文字列に一致するすべての要素を選択します。
要素はドキュメント(HTML)の上から下の順に選択されます。
一致する要素がない場合は空の選択を返します。
すべての段落要素を選択するには次のようにします。
1 |
var p = d3.selectAll("p"); |
また、引数のセレクタは文字列以外に、要素の配列を指定することができます。
例えば、すべてのチェックボックを ON にするには、次のようにします。
1 2 3 4 5 6 7 8 |
<input type="checkbox" name="check">チェック1</input> <input type="checkbox" name="check">チェック2</input> <input type="checkbox" name="check">チェック3</input> <script> var checkboxes = document.getElementsByName("check"); d3.selectAll(checkboxes).attr("checked","checked"); </script> |
2−3.selection.select(selector)
選択された要素(selection)ごとに、指定されたセレクタ文字列(select(selector))に一致する最初の子孫要素を選択します。
複数の要素がセレクタと一致する場合、ドキュメント順(上から下)で最初に一致する要素のみ選択されます。
例えば、各divの最初の段落(p要素)にスタイルを当てる場合は、次のようにします。
1 2 3 |
d3.selectAll("div").select("p") .attr("class", "bar") .style("color", "white"); |
また、引数のセレクタには関数も指定することができます。
例えば、各div要素の最初のチェックボックスを ON にするには、次のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div> <input type="checkbox" name="check">div1 チェック1</input> <input type="checkbox" name="check">div1 チェック2</input> <input type="checkbox" name="check">div1 チェック3</input> </div> <div> <input type="checkbox" name="check">div2 チェック1</input> <input type="checkbox" name="check">div2 チェック2</input> <input type="checkbox" name="check">div2 チェック3</input> </div> <script> var checkboxes = d3.selectAll("div").select( function(){ return this.firstElementChild; }); checkboxes.attr("checked","checked"); </script> |
2−4.selection.selectAll(selector)
選択された要素(selection)ごとに、引数で指定されたセレクタ文字列(selectAll(selector))に一致する全ての子孫要素を選択します。
例えば、各div要素内の全ての各段落を選択するには、次のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<div> <p>div1 段落1</p> <p>div1 段落2</p> <p>div1 段落3</p> </div> <div> <p>div2 段落1</p> <p>div2 段落2</p> <p>div2 段落3</p> </div> <script> d3.selectAll("div").selectAll("p") .attr("class", "bar") .style("color", "white"); </script> |
また、引数で指定するセレクタは関数を指定することもできます。
例えば、各段落要素(p)内の 全てのチェックボックを選択する場合は、次のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<div> <input type="checkbox" name="check">div1 チェック1</input> <input type="checkbox" name="check">div1 チェック2</input> <input type="checkbox" name="check">div1 チェック3</input> </div> <div> <input type="checkbox" name="check">div2 チェック1</input> <input type="checkbox" name="check">div2 チェック2</input> <input type="checkbox" name="check">div2 チェック3</input> </div> <script> var checkboxes = d3.selectAll("div").selectAll( function(){ var inputs = [this.children[0],this.children[1],this.children[2]]; return inputs; }); checkboxes.attr("checked","checked"); </script> |
2−5.selection.filter(filter)
選択された要素(selection)をフィルタリングし、一致する要素(true)のみ返します。
フィルタは、セレクタ文字列または関数を指定することができます。
例えば、テーブルの偶数行のみフィルタリングするには、次のようにします。
1 2 |
① var even_tr = d3.selectAll("tr").filter(":nth-child(even)"); |
関数を使う場合
1 2 |
② var even_tr = d3.selectAll("tr").filter(function(d, i) { return i & 1; }); |
また、フィルタ前後でインデックスを同じにしたい場合は、filterではなく、select を使い次のようにします。
1 2 |
③ var even_tr = d3.selectAll("tr").select(function(d, i) { return i & 1 ? this : null; }); |
Demoでは、5行のうち偶数行のみ(2行目と4行目)選択されます。
filterを使った①と②の場合、選択後の各要素のインデックスは、0と1のため、元のインデックスが保持されていません。
次は、selectを使った場合の、選択後の各要素のインデックスです。
インデックスが1(2行目)と3(4行目)となっているため、選択前の5行あった状態のインデッックスが保持されていることが分かります。
①〜③の各 Demoは以下となります。
2−6.selection.merge(other)
選択された要素同士をマージします。
主に、データ結合の後に新規生成された要素(enter)と既存要素の更新(update)をマージするために使用されます。
2−7.d3.matcher(selector)
引数で指定されたセレクタと要素が一致する場合にtrueを返します。
このメソッドは、selection.filterが内部的に使用します。
次のようになります。
1 |
var div = selection.filter("div"); |
1 |
var div = selection.filter(d3.matcher("div")); |
2−8.d3.selector(selector)
引数で指定されたセレクタに一致する最初の子孫要素を返します。
このメソッドは、selection.selectが内部的に使用します。
次のようになります。
1 |
var p = selection.select(“p”); |
1 |
var p = selection.select(d3.selector(“p”)); |
2−9.d3.selectorAll(selector)
引数で指定されたセレクタに一致するすべての子孫要素を返します。
このメソッドは、selection.selectAllが内部的に使用します。
次のようになります。
1 |
var p = selection.selectAll(“p”); |
1 |
var p = selection.selectAll(d3.selectorAll(“p”)); |
2−10.d3.window(node)
引数で指定されたノードの所有者ウィンドウを返します。
2−11.d3.style(node, name)
引数で指定されたノード・指定された名前を持つ、スタイルのプロパティ値を返します。
3.要素を変更するメソッド一覧
3−1.selection.attr(name[, value])
選択した要素の属性(name)を指定した値(value)に設定します。
valueにnullを指定すると、その属性が削除されます。
また、属性(name) のみ指定した場合、現在の値を返します。
属性の追加
要素に属性(name)を追加するには、次のようにします。
1 |
d3.select("#add").attr("name", "add-name"); |
変更前・後の htmlは次のようになります。
1 2 3 4 |
// 変更前 <p id="add">name属性を追加</p> // 変更後 <p id="add" name="add-name">name属性を追加</p> |
変更後の p要素に name=”add-name” が設定されています。
属性の削除(valueにnullを指定)
要素の属性(name)を削除するには、次のようにします。
1 |
d3.select("#delete").attr("name", null); |
変更前・後の htmlは次のようになります。
1 2 3 4 |
// 変更前 <p id="delete" name="delete-name">name属性を削除</p> // 変更後 <p id="delete">name属性を削除</p> |
変更後のp要素から、 name属性が削除されています。
属性の参照
要素の属性(name)に設定されている値を参照するには、次のようにします。
1 2 3 4 |
//javascript var show_attr = d3.select("#show").attr("name"); // html <p id="show" name="show-name">name属性を参照</p> |
この場合、変数show_attrには、属性(nameの値)”show-name” が代入されます。
3−2.selection.classed(names[, value])
選択した要素に、指定したクラス(names)を追加します。
引数(value)に true を指定した場合のみ、クラスが追加されます。
また、複数クラスを一度に追加することもでき、その場合、各クラスを半角スペースで区切ります。 “class1 class2”
既に設定されているクラスを削除する時は、引数(value)に false を指定します。
namesのみ指定した場合は、指定したクラスが既に設定されているか確認することができます。
クラスの追加
クラス(blueとbold)を追加するには、次のようにします。
1 |
d3.select("#add").classed("blue bold", true); |
変更前・後のhtmlは次のようになります。
1 2 3 4 |
// 変更前 <p id="add">class blue bold を追加</p> // 変更後 <p id="add" class="blue bold">class blue bold を追加</p> |
クラスに、”blue bold” が追加されます。
クラスの削除
クラス blueとboldが設定済みの状態から、boldのみ削除する場合は次のようにします。
1 |
d3.select("#delete").classed("bold", false); |
変更前・後のhtmlは次のようになります。
1 2 3 4 |
// 変更前 <p id="delete" class="blue bold">class bold を削除</p> // 変更後 <p id="delete" class="blue">class bold を削除</p> |
クラスから、 bold が削除されました。
クラスの設定確認
クラス bold が設定されているか確認するには次のようにします。
1 2 3 4 |
// javascript var exists_true = d3.select("#exists-true").classed("bold"); // html <p id="exists-true" class="blue bold">class boldの存在確認(true)</p> |
この場合、対象要素のクラスには、bold が設定されているので、変数 exists_trueには、 trueが代入されます。
もし、指定したクラスが設定されていない場合は、false が返ります。
クラスの追加(関数)
引数(value)には、関数を指定することもでき、戻り値は true もしくは false を設定します。
関数を使うとある条件の場合のみ、クラスを追加・削除する ということが行えます。
クラスの追加をランダムに行うには、次のようにします。
1 2 |
d3.select("#random").selectAll("p") .classed("blue", function() { return Math.random() > 0.5; }); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 変更前 <div id="random"> <p>① ランダムにclass属性 blue が追加されます</p> <p>② ランダムにclass属性 blue が追加されます</p> <p>③ ランダムにclass属性 blue が追加されます</p> <p>④ ランダムにclass属性 blue が追加されます</p> <p>⑤ ランダムにclass属性 blue が追加されます</p> </div> // 変更後 <div id="random"> <p class="blue">① ランダムにclass属性 blue が追加されます</p> <p class="blue">② ランダムにclass属性 blue が追加されます</p> <p>③ ランダムにclass属性 blue が追加されます</p> <p>④ ランダムにclass属性 blue が追加されます</p> <p class="blue">⑤ ランダムにclass属性 blue が追加されます</p> </div> |
変更後のp要素に、ランダムにクラス(blue)が追加されます。
3−3.selection.style(name[, value[, priority]])
選択した要素に、指定した名前(name)・値(value)のstyleプロパティを設定します。
valueにnull値を指定すると、対象(name)のstyleプロパティが削除されます。
また、valueには関数も指定でき、戻り値は styleプロパティの設定値として使用されます。
nameのみ指定した場合は、styleプロパティの値が返されます。
styleの追加
style(”font-weight”,”bold” )を追加する場合は、次のようにします。
1 |
d3.select("#add").style("font-weight","bold"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <div id="add"><p> styleで font-weight:bold を追加</p></div> // 変更後 <div id="add" style="font-weight: bold;"><p> styleで font-weight:bold を追加</p></div> |
div要素のstyleに、”font-weight”,”bold” が設定されます。
styleの削除
style(”font-weight”)を削除するには、次のようにします。
1 |
d3.select("#delete").style("font-weight",null); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <div id="delete" style="font-weight:bold;"><p> styleの font-weight を削除</p></div> // 変更後 <div id="delete" style=""><p> styleの font-weight を削除</p></div> |
div要素のstyleから、”font-weight” が削除されました。
styleの参照
style(”font-weight”)に設定されている値を参照するには、次のようにします。
1 2 3 4 |
// javascript var show = d3.select("#show").style("font-weight"); // html <div id="show" style="font-weight:bold;"><p> styleの font-weight の値を参照</p></div> |
変数 show には、”bold” が代入されます。
styleの追加(関数)
ランダムにstyle(”font-weight”)を設定するには、次のようにします。
1 2 3 4 5 6 7 8 |
d3.select("#add-function").selectAll("p") .style("font-weight", function(){ if ( Math.random() > 0.5) { return "none"; }else{ return "bold"; } }); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 変更前 <div id="add-function"> <p>① ランダムに font-weight:bold が追加されます</p> <p>② ランダムに font-weight:bold が追加されます</p> <p>③ ランダムに font-weight:bold が追加されます</p> <p>④ ランダムに font-weight:bold が追加されます</p> <p>⑤ ランダムに font-weight:bold が追加されます</p> </div> // 変更後 <div id="add-function"> <p>① ランダムに font-weight:bold が追加されます</p> <p>② ランダムに font-weight:bold が追加されます</p> <p style="font-weight: bold;">③ ランダムに font-weight:bold が追加されます</p> <p style="font-weight: bold;">④ ランダムに font-weight:bold が追加されます</p> <p style="font-weight: bold;">⑤ ランダムに font-weight:bold が追加されます</p> </div> |
ランダムにstyleが設定されました。
3−4.selection.property(name[, value])
attrやstyleメソッドで設定できない属性には、propertyメソッドを使用します。
選択した要素に、指定したプロパティ名(name)とその値(value)を設定します。
valueに、null を指定すると対象のプロパティが削除されます。
また、nameのみ指定した場合、そのプロパティ値を返します。
プロパティの追加
テキストボックスに値を設定(value)するには、次のようにします。
1 2 3 4 |
// javascript d3.select("#add-text").property("value", "テキストを追加"); //html <input type="text" id="add-text"> |
チェックボックスを、オンにするには、次のようにします。
1 2 3 4 |
// javascript d3.select("#add-checkbox").property("checked", "checked"); // html <input type="checkbox" id="add-checkbox" value="1">チェックボックス |
プロパティの変更
プロパティの追加と同様の手順で設定します。
プロパティの参照
プロパティ(value)に設定されている値を参照するには、次のようにします。
1 2 3 4 |
// javascript var text_val = d3.select("#show-text").property("value"); // html <input type="text" id="show-text" value="show-text"> |
変数 text_val には、”show-text” が代入されます。
3−5.selection.text([value])
選択した要素の、テキストコンテンツを指定した値(value)に設定し、子要素を置き換えます。
valueには、関数を指定することができ、戻り値は各要素のテキストコンテンツを設定するために使用されます。
また、value に null を指定すると、コンテンツは消去されます。
valueを指定しない場合は、選択した要素のテキストコンテンツを返します。
テキストの追加
段落要素(p)にテキスト追加するには、次のようにします。
1 |
d3.select("#add-text").text("テキストを追加"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <p id="add-text"></p> // 変更後 <p id="add-text">テキストを追加</p> |
テキストの変更
テキストの追加と同じ方法で行います。
テキストの削除
テキストを削除するには、valueに nullを指定します。
1 |
d3.select("#del-text").text(null); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <p id="del-text">delete text<p> // 変更後 <p id="del-text"></p> |
テキストの参照
1 2 3 4 |
// javascript var text_val = d3.select("#show-text").text(); // html <p id="show-text">show text</p> |
変数 text_val には、”show text” が代入されます。
テキストの追加(関数)
関数で現在年月日を求め、その結果をテキストに設定するには、次のようにします。
1 2 3 4 5 6 7 |
d3.select("#add-func-text").text(function(){ var date = new Date(); var y = date.getFullYear(); var m = date.getMonth()+1; var d = date.getDate(); return y + "/" + m + "/" + d; }); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <p id="add-func-text"></p> // 変更後 <p id="add-func-text">2018/8/1</p> |
3−6.selection.html([value])
valueに指定した値で、選択した要素の子要素のhtmlを置き換えます。
valueには文字列の他に関数を指定することができ、戻り値は子要素のhtmlを設定するために使用されます。
また、value に null を指定するとコンテンツは消去されます。
valueを指定しない場合は、子要素のhtmlを返します。
htmlメソッドは、innerHTMLを操作するため、svgやhtml以外の要素で、innerHTMLをサポートしていない要素については、使用することができません。
htmlの追加
選択した要素の、子要素として段落要素(p)を追加するには、次のようにします。
1 |
d3.select("#add").html("<p>テキストを追加</p>"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 |
// 変更前 <div id="add"></div> // 変更後 <div id="add"><p>テキストを追加</p></div> |
htmlの更新
既に子要素が存在する、div要素を更新するには次のようにします。
1 |
d3.select("#modify").html("<p>modify text1</p><p>modify text2</p>"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 |
// 変更前 <div id="modify"> <p>modify text</p> </div> // 変更後 <div id="modify"> <p>modify text1</p> <p>modify text2</p> </div> |
変更前の子要素が、置き換えられました。
htmlの削除
選択した要素の子要素を削除するには、次のようにします。
1 |
d3.select("#delete").html(null); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 |
// 変更前 <div id="delete"> <p>delete text<p> </div> // 変更後 <div id="delete"></div> |
htmlの参照
選択した要素の子要素を参照するには、次のようにします。
1 2 3 4 5 6 7 |
// javascript var text_val = d3.select("#show").html(); // html <div id="show"> <p>show text</p> </div> |
変数 text_val には、”<p>show text</p>” が代入されます。
3−7.selection.append(type)
選択した要素の最後の子として、新しい要素を追加します。
typeには文字列の他に関数も指定でき、戻り値は追加する要素を返す必要があります。 (新しい要素、もしくは既存の要素)
例えば、全てのdiv要素に段落要素を追加するには、次のようにします。
1 |
d3.selectAll("div").append("p"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 |
// 変更前 <div id="div-1"></div> <div id="div-2"></div> // 変更後 <div id="div-1"><p></p></div> <div id="div-2"><p></p></div> |
※真っ白なページが表示されますが、ページのソースを表示すると、変更後の状態を確認できます。
3−8.selection.insert(type[, before])
typeで指定した要素を追加します。
beforeは、追加する要素の場所を指定します。デフォルト(未指定)の場合は、null となり、追加する要素は、選択した要素の最後の子として追加されます。
beforeを指定した場合は、指定した要素の前の要素として追加されます。
例えば、before を指定しない場合は、次のようになります。
1 |
d3.select("div").insert("p"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 |
// 変更前 <div id="div-1"> <table></table> </div> // 変更後 <div id="div-1"> <table></table> <p></p> </div> |
段落要素(p)は、選択したdiv要素の最後の子として追加されます。
次に、 beforeを指定した場合は、次のようになります。
1 |
d3.select("div").insert("p","table"); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 |
// 変更前 <div id="div-1"> <table></table> </div> // 変更後 <div id="div-1"> <p></p> <table></table> </div> |
before で table要素を指定しているので、table要素の前に段落要素(p)が追加されます。
3−9.selection.remove()
選択した要素をドキュメントから削除します。
div要素内のすべての段落要素(p)を削除するには、次のようにします。
1 |
d3.select("div").selectAll("p").remove(); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 |
// 変更前 <div> <p>段落1</p> <p>段落2</p> <p>段落3</p> </div> // 変更後 <div></div> |
3−10.selection.clone([deep])
選択した要素の複製を生成し、選択した要素の直後に挿入します。
また、戻り値として追加した要素の選択を返します。
deepを有効(true)にした場合は、選択した要素の子孫ノードも同様に複製されます。
要素を複製する場合は、次のようにします。deepは未指定(false)
1 |
d3.select("div").clone(); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 |
// 変更前 <div> <p>clone test.</p> </div> // 変更後 <div> <p>clone test.</p> </div> <div></div> |
選択したdiv要素のみ複製・追加されました。
次に、deepを有効にした場合です。
1 |
d3.select("div").clone(true); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 |
// 変更前 <div> <p>clone test.</p> </div> // 変更後 <div> <p>clone test.</p> </div> <div> <p>clone test.</p> </div> |
選択したdiv要素の子要素も含め複製され、追加されました。
Demoを表示(selection.clone)deep 無効
Demoを表示(selection.clone)deep 有効
3−11.selection.sort(compare)
選択した要素を、指定したソート順(compare)で並び替えます。
compareは、デフォルト(未指定)では昇順になり、2つの要素のデータaとbを渡して比較します。
戻り値は、負の値、正の値、またはゼロを返す必要があります。
負の値の場合
a は b の前になります。例えば、a = 1 、 b = 5 の場合は、1,5 と昇順の並びとなります。
正の値の場合
a は b の後ろになります。例えば、a = 1 、 b = 5 の場合は、5,1と降順の並びとなります。
ゼロの場合
a と b は等価とみなされます。
選択した段落要素(p)を降順に並び替える場合は、次のようにします。
1 |
d3.selectAll("p").sort(function(){return 1}); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 変更前 <div> <p>sort test 1.</p> <p>sort test 2.</p> <p>sort test 3.</p> <p>sort test 4.</p> <p>sort test 5.</p> </div> // 変更後 <div> <p>sort test 5.</p> <p>sort test 4.</p> <p>sort test 3.</p> <p>sort test 2.</p> <p>sort test 1.</p> </div> |
3−12.selection.raise()
選択した各要素を、親の最後の子として順番に再挿入します。
例えば、div要素内の最初の段落要素(p)を最後の子要素として再挿入するには次のようにします。
1 |
d3.select("div").select("p").raise(); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 変更前 <div> <p>段落1</p> <p>段落2</p> <p>段落3</p> </div> // 変更後 <div> <p>段落2</p> <p>段落3</p> <p>段落1</p> </div> |
3−13.selection.lower()
選択した各要素を親の最初の子として順番に再挿入します。
例えば、div要素内の最後の段落要素(p)を最初の子要素として再挿入するには次のようにします。
1 |
d3.select("#div-3").lower(); |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 変更前 <div> <p>段落1</p> <p>段落2</p> <p id="div-3">段落3</p> </div> // 変更後 <div> <p id="div-3">段落3</p> <p>段落1</p> <p>段落2</p> </div> |
3−14.d3.creator(name)
selection.append や selection.insertによって内部的に使用され、nameで指定した新しい要素を作成します。
appendでは次のように使用されています。
1 2 3 |
selection.append("div"); // 内部的に、creator を使用 selection.append(d3.creator("div")); |
4.データを結合するメソッド一覧
4−1.selection.data([data[, key]])
選択した要素に指定したデータ配列を結合し、対応する要素を追加または削除することができます。
データが要素に割り当てられると、そのデータはプロパティ__data__に格納されます。
例えば、二次元配列のデータを使って、tableを作成するには次のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// ① 結合するデータ var matrix = [ [ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12], [ 13, 14, 15, 16] ]; // ② body要素に、table・行(tr)要素を追加 var tr = d3.select("body") // body要素を選択 .append("table") // 選択したbody要素にtable要素を追加 .selectAll("tr") // table要素内のすべての行(tr)要素を選択 .data(matrix) // データを結合 .enter() // 新規に追加される要素を反映 .append("tr"); // tr要素を追加 // ③ 各tr要素に列(td)要素を追加 tr.selectAll("td") // すべての列(td)要素を選択 .data(function(d) { return d; }) // ②で結合したデータ配列の各値をデータとして指定 .enter() // 新規に追加される要素を反映 .append("td") // 列(td)要素を追加 .text(function(d) { return d; }); // 列(td)要素にテキストを設定 |
① 結合するデータを準備
今回は直接二次元配列を定義しましたが、csvやjsonなど外部から取得したデータでも大丈夫です。
② body要素に、table・行(tr)要素を追加
詳細はソースコードのコメントに記載しています。
ポイントは、.append(“table”)、.selectAll(“tr”)、.append(“tr”)、.enter() です。
.append(“table”)
ソースコードのhtmlには、body要素しか定義していないため、body要素配下にtable要素を追加します。
.selectAll(“tr”)
table要素内のすべての行(tr)を選択します。
ただし、ソースコードでは、trは定義していないため、新たに作成されるtr要素を選択するという意味になります。
.append(“tr”)
table要素に行(tr)要素を追加します。
2次元配列のデータから、行要素は4つ追加されます。
.enter()
データ配列から新規追加される、行要素をhtmlに反映(追加)します。
enterを指定しないと追加した行要素は、htmlに反映されません。
③ 各tr要素に列(td)要素を追加
詳細はソースコードのコメントに記載しています。
ポイントも②と同じです。
次に、第二引数のkeyの使い方です。
keyを指定すると、データは一致するキーを持つ要素に割り当てられます。
例えば、div要素のid値に一致するデータを割り当てる場合は次のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<body> <div id="apple"></div> <div id="orange"></div> <div id="grapes"></div> <script> // ① 結合するデータ var data = [ {name: "grapes", name_jp: "ぶどう"}, {name: "apple", name_jp: "りんご"}, {name: "orange", name_jp: "オレンジ"} ]; // ② divのidと一致するデータを結合 d3.selectAll("div") .data(data, function(d) { var result = d ? d.name : this.id; // データ配列のnameとdiv要素のidを比較 return result; }) .text(function(d) { return d.name_jp; // 条件に一致したdiv要素のtextに、データ配列のname_jpを設定 }); </script> </body> |
① 結合するデータを準備
今回は各配列内に、nameとname_jpを定義したデータを使用します。
② divのidと一致するデータを結合
処理の詳細は、ソースのコメントに記載した通りです。
ポイントは、引数のkeyに関数を指定しているところです。
1 2 3 4 |
.data(data, function(d) { var result = d ? d.name : this.id; // データ配列のnameとdiv要素のidを比較 return result; }) |
ここで、一致する条件を指定します。
今回は、「データ配列のnameとdivのidが一致」という条件を指定しました。
そして条件に一致したdiv要素に対して、以下でテキストを設定しています。
1 2 3 |
.text(function(d) { return d.name_jp; // 条件に一致したdiv要素のtextに、データ配列のname_jpを設定 }); |
次に、dataで結合した要素の追加・更新・削除の一連の動きを確認します。
追加
dataで結合した際に、該当する要素が存在しない場合、新たに要素が追加されます。
更新
dataで結合した際に、同じ要素がある場合は再利用されます。
削除
dataで結合した際に、更新(再利用)されずに余った要素は削除する必要があります。
削除しないと、その要素はそのままドキュメントに残ったままになります。
例として、SVGで3つ円を描画した後に、同じ要素(circle)を使って5つ円を描いた場合、どのようになるか試してみます。
最初に3つ円を描画すると、赤い円が3つ描画されます。
var data = [20,30,40];
次に、同じ要素を選択して、5つ円を描くと、青と緑の円ができ縁も黒で塗りつぶされています。
var data2 = [10,30,40,50,60];
青の円が、最初に描画した3つの円を更新したものです。
緑の円が、新たに追加した要素です。
また、全ての縁が黒くなっているのは、2回目の描画対象となった印です。
このように、最初に描画した要素が再利用されたことが分かりました。
ちなみに、要素の削除(circle.exit().remove();)を行なっていますが、今回は全て再利用したため削除された要素はありません。
ソースコード(body以下)とDemoは以下となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<body> <svg></svg> <script> // 初期描画 var data = [20,30,40]; var svg = d3.select("svg"); var circle = svg.selectAll("circle") .data(data) .enter() .append("circle") .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "red"); // 書き換え var data2 = [10,30,40,50,60]; circle = svg.selectAll("circle") .data(data2) .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "blue"); circle.exit().remove(); circle = circle.enter() .append("circle") .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "green") .merge(circle) .style("stroke", "black"); </script> </body> |
次は、dataのkeyに対応する要素のみ再利用したいと思います。
dataメソッドのkeyを指定することで指定した要素を再利用できるようになります。
前回との違いは、再描画する際に dataのkey を指定しているところです。
1 |
.data(data2, function(d) { return d; }) |
このようにkeyを指定すると入力した要素と一致する要素が更新対象になります。
最初に描画したdata(3つの円)と再描画したdata(5つの円)の 値は次の通りです。
var data = [20,30,40];
var data2 = [10,30,40,50,60];
この場合、値が一致する 30 と 40 の円のみ再利用されます。
20の円は再利用されないため、削除する必要があります。
実際に描画すると次のようになります。
最初の3つの円
再描画後の5つの円
青い円が、再利用された要素になります。(30と40)
緑の円が、追加された要素になります。(10、50、60)
また、先ほどのkeyを指定しなかった場合と比べると(上:key指定なし、下:key指定あり)
最初の10の要素が再利用される、されないの違いがあることが分かります。
ソースコード(body以下)とDemoは以下となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<body> <svg></svg> <script> // 初期描画 var data = [20,30,40]; var svg = d3.select("svg"); var circle = svg.selectAll("circle") .data(data) .enter() .append("circle") .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "red"); // 書き換え var data2 = [10,30,40,50,60]; circle = svg.selectAll("circle") .data(data2, function(d) { return d; }) .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "blue"); circle.exit().remove(); circle = circle.enter() .append("circle") .attr("cy", 60) .attr("cx", function(d, i) { return d + (i * 30); }) .attr("r", function(d) { return Math.sqrt(d); }) .style("fill", "green") .merge(circle) .style("stroke", "black"); </script> </body> |
次に要素の削除を確認します。
以下の例では、最初に5つの円を描画し、再描画で3つの円を描画しています。
keyは指定していないため、再描画時に不要な要素の削除を行わない場合は、最初に描画した要素が残ってしまいます。
Demoの通り、不要な要素は削除(circle.exit().remove();)しないと残ることが分かります。(赤い円が初期描画の円になります)
4−2.selection.enter()
4−1で扱った通り、data()で結合した際に作成された、新規要素を反映するために使用します。
例えば、文字列の配列からdiv要素を作成するには、次のようにします。
1 2 3 4 5 6 7 8 9 |
<script> var data = ["text 1","text 2","text 3"]; var div = d3.select("body") .selectAll("div") .data(data) .enter().append("div") .text(function(d) { return d; }); </script> |
変更前・後のhtmlは、次のようになります。
1 2 3 4 5 6 7 8 9 |
// 変更前 <body> </body> // 変更後 <body> <div>text 1</div> <div>text 2</div> <div>text 3</div> </body> |
4−3.selection.exit()
余分な要素を削除するために使用されます。
例えば、div要素が3つあるhtmlに対して、selection.data を使ってデータを書き換えます。
変更後はdiv要素が2つに減った場合、何もしないと元々あった3つ目のdiv要素は残ったままになります。
この3つ目の要素が必要無い「余分な要素」の場合、exit を使うと削除することができます。
例えば、余分な要素を削除するには次のようにします。
1 |
削除対象の要素.exit().remove(); |
4−4.selection.datum([value])
選択した各要素にバインドされたデータを取得または設定します。
selection.dataとは異なり、このメソッドでデータを設定してもドキュメント上変更は行われません。
nullを設定するとバインドされたデータが削除されます。
また、引数valueを指定しない場合は、現在の設定値が返されます。
例えば、3つのdiv要素があり、それぞれ text 1、text 2、text 3 とテキストが設定されている要素がある場合、その要素を選択し、datumでデータプロパティを再設定してもテキストの表示内容は変わりません。
次のように要素がもつ__data__プロパティの内容が変わります。
datumで変更後のブラウザ上の表示
datumで変更後の__data__プロパティ。div要素(text 1)
このように、datumで変更すると対象要素の__data__プロパティの値が変更されます。
5.イベント処理
5−1.selection.on(typenames[, listener[, capture]])
選択した要素にイベントを登録したり、登録済みのイベントを削除することができます。
各引数の詳細は次の通りです。
typenames
“click”や”mouseover”など、ブラウザでサポートされているすべてのDOMイベントタイプを使用できます。
また、オプションでピリオド(.)を使用して名前をつけることができます。
例えば、click.btn1 などclickイベントに対して個別に名前をつけることができます。
listener(オプション)
イベントが発行された際に行う処理を定義します。
例えば、匿名関数 function(d,i){} で処理を定義することもできます。
この時の引数 d は現在のデータ、iは現在のインデックスが渡されます。
リスナーは、常に要素の最新データを参照しますが、インデックスはリスナーが割当たると固定されます。
インデッックスを更新するには、リスナーを再割り当てする必要があります。
また、nullを指定すると、対象のイベント(typenames)の登録が削除されます。
capture(オプション)
W3CのuseCaptureフラグに対応するキャプチャフラグを指定することができます。
次にイベントの登録・削除を行います。
なお、各処理のDemoはこちらから表示できます。
① 1つのイベントを登録
次の例では、ボタン(id=”ev1-btn”)にclickイベントを登録しています。
1 2 3 4 |
// html <button id="ev1-btn">単一イベント</button> //javascript d3.select("#ev1-btn").on("click", function(d,i){ alert("btn1がClickされました。");}); |
② 複数イベントを登録
次の例では、ボタンに2つのclickイベント( click.ev1、click.ev2 )を登録しています。
この場合、ボタンのクリックで、2つのイベントが実行されます。(実行は登録順で行われます。)
1 2 3 4 5 |
// html <button id="ev3-btn">削除(clickの指定したイベント)</button> // javascript d3.select("#ev2-btn").on("click.ev1", function(d,i){ alert("click event1");}); d3.select("#ev2-btn").on("click.ev2", function(d,i){ alert("click event2");}); |
③ 指定したイベントを削除
次の例では、要素からclickイベント(click.ev1)のみ削除しています。
この状態で実行すると、click.ev2 のイベントのみ実行されます。
1 2 3 4 5 6 7 |
// html <button id="ev3-btn">削除(clickの指定したイベント)</button> // javascript d3.select("#ev3-btn").on("click.ev1", function(d,i){ alert("click event1");}); d3.select("#ev3-btn").on("click.ev2", function(d,i){ alert("click event2");}); // 削除 d3.select("#ev3-btn").on("click.ev1", null); |
まず、ボタン(id=”ev3-btn”)に 2つのイベント(click.ev1、click.ev2)を登録します。
その後、イベント(”click.ev1″)に null が指定されているので、このイベントは削除されます。
Demoを実行すると、イベント(”click.ev2″)のみ実行されます。
④ 特定の名前をもつイベントのみ削除
次の例では、click、mouseover に関わらず、イベント.名前 で登録した 「.名前」に該当するイベントが削除されます。
1 2 3 4 5 6 7 8 9 |
// html <button id="ev4-btn">削除(clickの全てのイベント)</button> // javascript var div_ev4 = d3.select("#ev4-btn"); div_ev4.on("click.ev4_1", function(d,i){ alert("click event1");}); div_ev4.on("click.ev4_2", function(d,i){ alert("click event2");}); div_ev4.on("mouseover.ev4_1", function(d,i){ alert("mouseover event");}); div_ev4.on(".ev4_1", null); |
最初にボタン(id=”ev4-btn”)に対して、3つのイベントを登録しています。
・”click.ev4_1″
・”click.ev4_2″
・”mouseover.ev4_1″
次に、イベント(”.ev4_1″)に対してnull を設定しているため、イベント名に”.ev4_1″をもつ、以下のイベントが削除されます。
・click.ev4_1
・mouseover.ev4_1
そのため、Demoを実行すると、イベント(”click.ev4_2″)のみ実行されます。
⑤ 名前のない全てのイベントを削除
名前のないイベントとは、click.name の .name が定義されていないイベントです。
名前のないイベントを全て削除するには、typenames に “.”、listener に null を指定します。
1 2 3 4 5 6 7 8 9 |
// html <button id="ev5-btn">削除(名前のない全てのイベント)</button> // javascript var div_ev5 = d3.select("#ev5-btn"); div_ev5.on("click", function(d,i){ alert("click event1");}); div_ev5.on("click.ev5_2", function(d,i){ alert("click event2");}); div_ev5.on("mouseover", function(d,i){ alert("mouseover event");}); div_ev5.on(".", null); |
最初にボタン(id=”ev5-btn”)に、3つのイベント(”click”、”click.ev5_2″、”mouseover”)を定義しています。
次に、div_ev5.on(“.”, null); で、名前のない全てのイベントを削除しているため、Demoを実行すると、イベント(”click.ev5_2″)のみ実行されます。