回答:
私はマイク自身から正しい答えを見つけました:
データを単一のSVG要素にバインドしたい場合は、
(...).data([data])
または
(...).datum(data)
データを複数のSVG要素にバインドしたい場合
(...).data(data).enter().append("svg")
.....
enter()バインドするときにSVG要素よりも多くのデータ配列要素がある場合、d3は残りの配列要素を新しく作成されたSVG要素にバインドします。
これを少し調べたところ、SOに関する回答は、入力パラメーターを使用して呼び出す場合のケースのみを対象selection.dataとselection.datumしているため、完全ではないことがわかりましたdata。そのシナリオでも、選択が単一の要素である場合と複数の要素が含まれている場合の2つの動作は異なります。さらに、これらのメソッドはどちらも、選択内のバインドされたデータ/データをクエリするために、入力引数なしで呼び出すこともできます。その場合、これらのメソッドは再び異なる動作をし、異なるものを返します。
編集-この質問に対する少し詳細な回答をここに投稿しましたが、以下の投稿では、2つの方法に関するすべての重要なポイントと、それらが互いにどのように異なるかをかなり捉えています。
供給時 dataのように入力引数
selection.data(data)実行しようとするの要素の間でデータを-参加dataの作成に結果として得られる選択した配列enter()、exit()およびupdate()それ以降にに操作できることを選択。この最終結果は、配列を渡すと、data = [1,2,3]個々のデータ要素(つまりデータム)を選択範囲に結合しようとする試みです。セレクションの各要素は、dataそれにバインドされた単一のデータム要素のみを持ちます。
selection.datum(data)データ結合プロセスを完全にバイパスします。これdataは、データ結合の場合のように分割せずに、全体を選択範囲のすべての要素に割り当てるだけです。したがって、配列全体data = [1, 2, 3]を内のすべてのDOM要素にバインドするselection場合selection.datum(data)は、これを実現します。
警告:これは
selection.datum(data)と同等であると信じてselection.data([data])いますが、これはselectionが1つの要素を含む場合にのみ当てはまります 。selection複数のDOM要素が含まれている場合は、選択範囲内のすべての要素にselection.datum(data)全体をバインドしますdata。対照的に、selection.data([data])全体dataをの最初の要素にのみバインドしますselection。これは、のデータ結合動作と一致していますselection.data。
data入力引数を指定しない場合
selection.data()選択内の各要素のバインドされたデータを取得し、それらを返される配列に結合します。だから、あなたがあればselectionデータを3つのDOM要素を含み"a"、"b"かつ"c"、それぞれのそれぞれに結合されたselection.data()リターン["a", "b", "c"]。selectionが(例として)データムが"a"バインドされた単一の要素である場合、selection.data()は戻り["a"]、"a"一部のユーザーが期待するものとは異なることに注意することが重要です。
selection.datum()選択の最初の要素にバインドされたデータムを返すと定義されているため、単一の選択に対してのみ意味があります。したがって、上記の例では"a"、バインドされたデータムがとのDOM要素で構成される選択を使用する"b"と"c"、selection.datum()単にが返され"a"ます。
selectionが単一の要素を持っている場合でも、異なる値selection.datum()をselection.data()返すことに注意してください。前者は選択範囲のバインドされたデータ("a"上記の例)を返し、後者は配列(["a"]上記の例)内のバインドされたデータを返します。
うまくいけば、これがデータを入力引数として提供するときと、入力引数を提供しないことによってバインドされたデータを照会するときの両方で、どのようにselection.data、そしてselection.datum()互いに異なるかを明確にするのに役立ちます。
PS-これがどのように機能するかを理解する最良の方法は、Chromeで空白のHTMLドキュメントから開始してコンソールを開き、ドキュメントにいくつかの要素を追加してから、およびを使用selection.dataしてデータのバインドを開始することselection.datumです。場合によっては、読むよりも、何かを「理解」する方がはるかに簡単です。
ここにいくつかの良いリンクがあります:
D3の「data()」に関する良い議論: D3.jsがデータをノードにバインドする方法を理解する
後者について:
# selection.data([values[, key]])指定されたデータの配列を現在の選択と結合します。指定された値は、数値やオブジェクトの配列などのデータ値の配列、または値の配列を返す関数です。
...
# selection.datum([value])選択した各要素のバインドされたデータを取得または設定します。selection.dataメソッドとは異なり、このメソッドは結合を計算しません(したがって、選択の開始と終了を計算しません)。
これまでのところ、HamsterHueyの説明は最高だと思います。それを拡張し、私は間の違いの少なくとも一部を示すサンプル文書作成の違いを視覚的に表現するために与えるdataとしますdatum。
以下の回答は、これらの方法を使用することから得られた意見の詳細ですが、私が間違っている場合は訂正させていただきます。
この例は、このフィドルの下または下で実行できます。
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
datum結合を行わないので、それを理解する方が簡単だと思いますが、もちろんこれは、異なるユースケースがあることも意味します。
大きな違いは1つありますが(それ以上ありますが)、それdataはd3グラフで(ライブ)更新を行う自然な方法であるという事実です。
datum一方、静的な表現にはより適しているように思えます。たとえば、以下の例では、元の配列でループし、次のようにインデックスでデータにアクセスすることで、同じ結果を得ることができます。
data.map((n, i) => {
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node-${n} => data: ${d[i]}`);
});
ここで試してください:https : //jsfiddle.net/gleezer/e4m6j2d8/6/
ここでも、Enter / Update / Exitパターンから生じる精神的負担から解放されているので、これは理解しやすい方法だと思いますが、選択を更新または変更する必要があるとすぐに、確実にに頼る方が良いでしょう.data()。
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
/* Ignore all the css */
html {
font-family: arial;
}
.l {
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
margin: 10px 0;
}
.l-a {
background: #cf58e4;
}
.l-b {
background: #42e4e4;
}
.a {
border-bottom: 2px solid #cf58e4;
}
.b {
border-bottom: 2px solid #42e4e4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>
<div style="margin-bottom: 20px;">
<span class="l l-a"></span> .datum() <br />
<span class="l l-b"></span> .data()
</div>
<div id="root"></div>