跳到內容

加入資料

有關簡介,請參閱 用連接思考selection.join 筆記本

selection.data(data, key)

原始碼 · 將指定的 資料 陣列與選取的元素繫結,傳回新的選取,代表 更新 選取:成功繫結至資料的元素。同時在傳回的選取上定義 進入離開 選取,可用於新增或移除元素以符合新的資料。指定的 資料 是任意值的陣列(例如數字或物件),或傳回每組值的陣列的函式。當資料指定給元素時,會儲存在屬性 __data__ 中,因此資料會「黏著」,並可在重新選取時取得。

資料 是針對選取中的每組指定的。如果選取有多組(例如 d3.selectAll 接著 selection.selectAll),則 資料 通常應指定為函式。此函式會針對每組依序評估,傳入組的父資料項(d,可能未定義)、組索引(i)和選取的父節點(nodes),其中 this 為組的父元素。

搭配 selection.join(或更明確地搭配 selection.enterselection.exitselection.appendselection.remove),selection.data 可用於進入、更新和離開元素以符合資料。例如,從數字矩陣建立 HTML 表格

js
const matrix = [
  [11975,  5871, 8916, 2868],
  [ 1951, 10048, 2060, 6171],
  [ 8010, 16145, 8090, 8045],
  [ 1013,   990,  940, 6907]
];

d3.select("body")
  .append("table")
  .selectAll("tr")
  .data(matrix)
  .join("tr")
  .selectAll("td")
  .data(d => d)
  .join("td")
    .text(d => d);

在此範例中,資料 函式是恆等函式:對於每個表格列,它會傳回資料矩陣中對應的列。

如果未指定 key 函數,則 data 中的第一個資料會指定給第一個選取的元素,第二個資料會指定給第二個選取的元素,依此類推。可以指定 key 函數來控制哪個資料會指定給哪個元素,取代預設的依索引順序連接,方法是為每個資料和元素計算一個字串識別碼。這個 key 函數會針對每個選取的元素依序評估,傳遞目前的資料 (d)、目前的索引值 (i) 和目前的群組 (nodes),其中 this 為目前的 DOM 元素 (nodes[i]); 回傳的字串是元素的 key。然後也會針對 data 中的每個新資料評估 key 函數,傳遞目前的資料 (d)、目前的索引值 (i) 和群組的新 data,其中 this 為群組的父層 DOM 元素;回傳的字串是資料的 key。具有特定 key 的資料會指定給具有相同 key 的元素。如果多個元素具有相同的 key,重複的元素會放入 exit 選取;如果多個資料具有相同的 key,重複的資料會放入 enter 選取。

例如,針對這個文件

html
<div id="Ford"></div>
<div id="Jarrah"></div>
<div id="Kwon"></div>
<div id="Locke"></div>
<div id="Reyes"></div>
<div id="Shephard"></div>

您可以使用 key 進行資料連接,如下所示

js
const data = [
  {name: "Locke", number: 4},
  {name: "Reyes", number: 8},
  {name: "Ford", number: 15},
  {name: "Jarrah", number: 16},
  {name: "Shephard", number: 23},
  {name: "Kwon", number: 42}
];

d3.selectAll("div")
  .data(data, function(d) { return d ? d.name : this.id; })
    .text(d => d.number);

這個範例 key 函數會使用資料 d(如果存在),否則會改用元素的 id 屬性。由於這些元素之前未繫結到資料,因此當針對選取的元素評估 key 函數時,資料 d 為 null,而當針對新資料評估 key 函數時,則為非 null。

updateenter 選取會以資料順序回傳,而 exit 選取會保留連接之前的選取順序。如果指定了 key 函數,選取中元素的順序可能與文件中的順序不符;視需要使用 selection.orderselection.sort。有關 key 函數如何影響連接的詳細資訊,請參閱 長條圖,第 2 部分物件恆常性

如果未指定 data,這個方法會回傳選取元素的資料陣列。

此方法無法用於清除綁定的資料;請改用 selection.datum

selection.join(enter, update, exit)

原始碼 · 根據先前由 selection.data 繫結的資料,新增、移除和重新排序元素,傳回 合併 的 enter 和 update 選取。此方法是 一般更新模式 的便利替代方案,取代 selection.enterselection.exitselection.appendselection.removeselection.order。例如

js
svg.selectAll("circle")
  .data(data)
  .join("circle")
    .attr("fill", "none")
    .attr("stroke", "black");

enter 函式可以指定為如上方的字串簡寫,等同於使用指定元素名稱的 selection.append。同樣地,可以指定選擇性的 updateexit 函式,其預設值分別為身分函式和呼叫 selection.remove。因此,上述簡寫等同於

js
svg.selectAll("circle")
  .data(data)
  .join(
    enter => enter.append("circle"),
    update => update,
    exit => exit.remove()
  )
    .attr("fill", "none")
    .attr("stroke", "black");

透過在 enter、update 和 exit 中傳遞個別函式,你可以更靈活地控制發生的事項。而且透過為 selection.data 指定 key 函式,你可以將 DOM 的變更降至最低,以最佳化效能。例如,為 enter 和 update 設定不同的填滿顏色

js
svg.selectAll("circle")
  .data(data)
  .join(
    enter => enter.append("circle").attr("fill", "green"),
    update => update.attr("fill", "blue")
  )
    .attr("stroke", "black");

enterupdate 函式傳回的選取會合併,然後由 selection.join 傳回。

你可以透過在 enterupdateexit 函式中建立轉場,為 enter、update 和 exit 加入動畫效果。如果 enterupdate 函式傳回轉場,其底層選取會合併,然後由 selection.join 傳回。exit 函式的傳回值不會使用。

更多資訊,請參閱 selection.join 筆記本

selection.enter()

原始碼 · 傳回 enter 選取:每個在選取中沒有對應 DOM 元素的資料的佔位符節點。(對於未由 selection.data 傳回的選取,enter 選取會是空的。)

enter 選取通常用於建立對應新資料的「遺失」元素。例如,從數字陣列建立 DIV 元素

js
const div = d3.select("body")
  .selectAll("div")
  .data([4, 8, 15, 16, 23, 42])
  .enter().append("div")
    .text(d => d);

如果主體最初是空的,上述程式碼將會建立六個新的 DIV 元素,依序將它們附加到主體,並將它們的文字內容指定為關聯的(字串強制轉換)數字

html
<div>4</div>
<div>8</div>
<div>15</div>
<div>16</div>
<div>23</div>
<div>42</div>

在概念上,輸入選取的佔位符是指向父元素的指標(在此範例中,為文件主體)。輸入選取通常只暫時用於附加元素,並且在附加後經常會與更新選取合併,以便可以對輸入和更新元素套用修改。

selection.exit()

來源 · 傳回退出選取:選取中現有的 DOM 元素,但未找到新的資料。(對於未由 selection.data 傳回的選取,退出選取會是空的。)

退出選取通常用於移除對應於舊資料的「多餘」元素。例如,使用新的數字陣列更新先前建立的 DIV 元素

js
div = div.data([1, 2, 4, 8, 16, 32], d => d);

由於已指定金鑰函數(作為身分函數),且新資料包含數字 [4, 8, 16],與文件中的現有元素相符,因此更新選取包含三個 DIV 元素。讓這些元素保持原樣,我們可以使用輸入選取為 [1, 2, 32] 附加新元素

js
div.enter().append("div").text(d => d);

同樣地,移除退出元素 [15, 23, 42]

js
div.exit().remove();

現在文件主體看起來像這樣

html
<div>1</div>
<div>2</div>
<div>4</div>
<div>8</div>
<div>16</div>
<div>32</div>

DOM 元素的順序與資料的順序相符,因為舊資料的順序和新資料的順序是一致的。如果新資料的順序不同,請使用 selection.order 重新排列 DOM 中的元素。請參閱 一般更新模式 筆記本,以進一步了解資料聯結。

selection.datum(value)

來源 · 取得或設定每個選取元素的繫結資料。與 selection.data 不同,此方法不會計算聯結,也不會影響索引或輸入和退出選取。

如果指定了,則會將元素的綁定資料設定為所有選取元素上指定的。如果是常數,則所有元素都會給予相同的資料;否則,如果是函式,則會依序為每個選取的元素評估,傳遞目前的資料 (d)、目前的索引 (i) 和目前的群組 (nodes),其中 this 為目前的 DOM 元素 (nodes[i])。然後使用函式來設定每個元素的新資料。空值會刪除綁定的資料。

如果沒有指定,則會傳回選取中第一個 (非空值) 元素的綁定資料。這通常只在您知道選取只包含一個元素時才實用。

此方法對於存取 HTML5 自訂資料屬性很有用。例如,給定下列元素

html
<ul id="list">
  <li data-username="shawnbot">Shawn Allen</li>
  <li data-username="mbostock">Mike Bostock</li>
</ul>

您可以透過將每個元素的資料設定為內建 dataset 屬性來公開自訂資料屬性

js
selection.datum(function() { return this.dataset; })

選取.merge(其他)

來源 · 傳回一個新的選取,將此選取與指定的其他選取或轉換合併。傳回的選取具有與此選取相同的群組數和父項。此選取中任何遺失的 (空值) 元素都會填入指定的選取中對應的元素 (如果存在,非空值)。(如果其他選取有額外的群組或父項,則會忽略這些群組或父項。)

此方法會由 選取.join 內部使用,以在繫結資料後合併 輸入更新 選取。您也可以明確合併,但請注意,由於合併是根據元素索引,因此您應該使用保留索引的運算,例如 選取.select,而不是 選取.filter。例如

js
const odd = selection.select(function(d, i) { return i & 1 ? this : null; ));
const even = selection.select(function(d, i) { return i & 1 ? null : this; ));
const merged = odd.merge(even);

請參閱 選取.data 以取得更多資訊。

不過,此方法並非用於串接任意選取:如果此選取和指定的其他選取在同一個索引處有 (非空值) 元素,則此選取的元素會在合併中傳回,而其他選取的元素會被忽略。