Skip to content

连接数据

🌐 Joining data

有关介绍,请参见 Thinking With Joinsselection.join 注意本

🌐 For an introduction, see Thinking With Joins and the selection.join notebook.

selection.data(data, key)

Source · 将指定的 data 数组与所选元素绑定,返回表示 update 选择的新选择:成功绑定到数据的元素。同时在返回的选择上定义了 enterexit 选择,可用于添加或移除元素以对应新的数据。指定的 data 是任意值的数组(例如 数字或对象),或者是返回每个组的值数组的函数。当数据分配给元素时,它会存储在属性 __data__ 中,从而使数据“粘性”并在重新选择时可用。

数据在选择中为每个组指定。如果选择包含多个组(例如 d3.selectAll 后跟 selection.selectAll),那么 数据 通常应作为一个函数来指定。该函数将按顺序为每个组计算,传入该组的父数据 (d,可能未定义)、组索引 (i) 和选择的父节点 (nodes),并且 this 指向该组的父元素。

🌐 The data is specified for each group in the selection. If the selection has multiple groups (such as d3.selectAll followed by selection.selectAll), then data should typically be specified as a function. This function will be evaluated for each group in order, being passed the group’s parent datum (d, which may be undefined), the group index (i), and the selection’s parent nodes (nodes), with this as the group’s parent element.

selection.join(或更明确地与 selection.enterselection.exitselection.appendselection.remove)结合使用时,selection.data 可以用于输入、更新和退出元素以匹配数据。例如,要从一个数字矩阵创建一个 HTML 表格:

🌐 In conjunction with selection.join (or more explicitly with selection.enter, selection.exit, selection.append and selection.remove), selection.data can be used to enter, update and exit elements to match data. For example, to create an HTML table from a matrix of numbers:

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);

在这个例子中,data 函数是恒等函数:对于每一行表格,它返回数据矩阵中对应的行。

🌐 In this example the data function is the identity function: for each table row, it returns the corresponding row from the data matrix.

If a key function is not specified, then the first datum in data is assigned to the first selected element, the second datum to the second selected element, and so on. A key function may be specified to control which datum is assigned to which element, replacing the default join-by-index, by computing a string identifier for each datum and element. This key function is evaluated for each selected element, in order, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]); the returned string is the element’s key. The key function is then also evaluated for each new datum in data, being passed the current datum (d), the current index (i), and the group’s new data, with this as the group’s parent DOM element; the returned string is the datum’s key. The datum for a given key is assigned to the element with the matching key. If multiple elements have the same key, the duplicate elements are put into the exit selection; if multiple data have the same key, the duplicate data are put into the enter selection.

例如,给定以下文档:

🌐 For example, given this document:

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>

你可以按如下方式按键连接数据:

🌐 You could join data by key as follows:

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);

这个示例键函数在存在数据 d 时使用它,否则回退到元素的 id 属性。由于这些元素之前没有绑定数据,当在选定元素上评估键函数时,数据 d 为 null,而在新数据上评估键函数时,数据 d 不为 null。

🌐 This example key function uses the datum d if present, and otherwise falls back to the element’s id property. Since these elements were not previously bound to data, the datum d is null when the key function is evaluated on selected elements, and non-null when the key function is evaluated on the new data.

updateenter 选择按数据顺序返回,而 exit 选择保留连接之前的选择顺序。如果指定了键函数,选择中元素的顺序可能与文档中的顺序不一致;根据需要使用 selection.orderselection.sort。有关键函数如何影响连接的更多信息,请参见 条形图,第2部分对象恒定性

🌐 The update and enter selections are returned in data order, while the exit selection preserves the selection order prior to the join. If a key function is specified, the order of elements in the selection may not match their order in the document; use selection.order or selection.sort as needed. For more on how the key function affects the join, see A Bar Chart, Part 2 and Object Constancy.

如果未指定 data,此方法将返回所选元素的数据数组。

🌐 If data is not specified, this method returns the array of data for the selected elements.

此方法无法用于清除绑定数据;请改用 selection.datum

🌐 This method cannot be used to clear bound data; use selection.datum instead.

selection.join(enter, update, exit)

来源 · 根据之前通过 selection.data 绑定的数据,添加、移除和重新排序元素,并返回 merged 的 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。因此,上述简写相当于:

🌐 The enter function may be specified as a string shorthand, as above, which is equivalent to selection.append with the given element name. Likewise, optional update and exit functions may be specified, which default to the identity function and calling selection.remove, respectively. The shorthand above is thus equivalent to:

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 指定一个键函数,你可以将对 DOM 的更改最小化,从而优化性能。例如,要为 enter 和 update 设置不同的填充颜色:

🌐 By passing separate functions on enter, update and exit, you have greater control over what happens. And by specifying a key function to selection.data, you can minimize changes to the DOM to optimize performance. For example, to set different fill colors for enter and 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 返回。

🌐 The selections returned by the enter and update functions are merged and then returned by selection.join.

你可以通过在 enterupdateexit 函数内创建过渡来为进入、更新和退出制作动画。如果 enterupdate 函数返回过渡,它们的底层选择会被合并,然后由 selection.join 返回。exit 函数的返回值不会被使用。

🌐 You can animate enter, update and exit by creating transitions inside the enter, update and exit functions. If the enter and update functions return transitions, their underlying selections are merged and then returned by selection.join. The return value of the exit function is not used.

更多内容,请参见 selection.join 注意本

🌐 For more, see the selection.join notebook.

selection.enter()

来源 · 返回进入选择:对于每个在选择中没有对应 DOM 元素的数据,返回占位节点。(对于不是由 selection.data 返回的选择,进入选择为空。)

进入选择通常用于创建与新数据对应的“缺失”元素。例如,从一个数字数组创建 DIV 元素:

🌐 The enter selection is typically used to create “missing” elements corresponding to new data. For example, to create DIV elements from an array of numbers:

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

如果主体最初为空,则上述代码将创建六个新的 DIV 元素,按顺序将它们附加到主体,并将其文本内容赋值为关联的(字符串强制转换的)数字:

🌐 If the body is initially empty, the above code will create six new DIV elements, append them to the body in-order, and assign their text content as the associated (string-coerced) number:

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

从概念上讲,enter 选择的占位符是指向父元素的指针(在此示例中为文档主体)。enter 选择通常仅用于暂时性地追加元素,并且在追加后通常会与更新选择合并,以便对进入和更新的元素都可以进行修改。

🌐 Conceptually, the enter selection’s placeholders are pointers to the parent element (in this example, the document body). The enter selection is typically only used transiently to append elements, and is often merged with the update selection after appending, such that modifications can be applied to both entering and updating elements.

selection.退出()

🌐 selection.exit()

来源 · 返回退出选择:选择中没有找到新数据的现有 DOM 元素。(对于不是由 selection.data 返回的选择,退出选择为空。)

退出选择通常用于移除对应于旧数据的“多余”元素。例如,要使用新的一组数字更新先前创建的 DIV 元素时:

🌐 The exit selection is typically used to remove “superfluous” elements corresponding to old data. For example, to update the DIV elements created previously with a new array of numbers:

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

由于指定了关键函数(作为身份函数),并且新数据包含与文档中现有元素匹配的数字 [4, 8, 16],更新选择包含三个 DIV 元素。在保留这些元素不变的情况下,我们可以使用 enter 选择为 [1, 2, 32] 添加新元素:

🌐 Since a key function was specified (as the identity function), and the new data contains the numbers [4, 8, 16] which match existing elements in the document, the update selection contains three DIV elements. Leaving those elements as-is, we can append new elements for [1, 2, 32] using the enter selection:

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

同样,要删除现有元素 [15, 23, 42]:

🌐 Likewise, to remove the exiting elements [15, 23, 42]:

js
div.exit().remove();

现在文档主体如下所示:

🌐 Now the document body looks like this:

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

DOM 元素的顺序与数据的顺序匹配,因为旧数据的顺序与新数据的顺序一致。如果新数据的顺序不同,请使用 selection.order 来重新排序 DOM 中的元素。有关数据连接的更多信息,请参见 通用更新模式 注意本。

🌐 The order of the DOM elements matches the order of the data because the old data’s order and the new data’s order were consistent. If the new data’s order is different, use selection.order to reorder the elements in the DOM. See the general update pattern notebook for more on data joins.

selection.datum(value)

来源 · 获取或设置每个选定元素的绑定数据。与 selection.data 不同,此方法不计算连接,也不影响索引或进入和退出选择。

如果指定了value,则将元素的绑定数据设置为在所有选定元素上指定的值。如果value是常量,则所有元素都分配相同的数据;否则,如果value是一个函数,它将按顺序为每个选定元素执行,函数的参数为当前数据(d)、当前索引(i)和当前组(nodes),而this为当前的 DOM 元素(nodes[i])。然后该函数用于设置每个元素的新数据。null 值将删除绑定的数据。

🌐 If a value is specified, sets the element’s bound data to the specified value on all selected elements. If the value is a constant, all elements are given the same datum; otherwise, if the value is a function, it is evaluated for each selected element, in order, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]). The function is then used to set each element’s new data. A null value will delete the bound data.

如果未指定value,则返回选择中第一个(非空)元素的绑定数据。通常仅在你知道选择中恰好包含一个元素时才有用。

🌐 If a value is not specified, returns the bound datum for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element.

此方法对于访问 HTML5 自定义数据属性 很有用。例如,给定以下元素:

🌐 This method is useful for accessing HTML5 custom data attributes. For example, given the following elements:

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

你可以通过将每个元素的数据设置为内置的 dataset 属性来公开自定义数据属性:

🌐 You can expose the custom data attributes by setting each element’s data as the built-in dataset property:

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

selection.merge(other)

来源 · 返回一个新的选择,将此选择与指定的 other 选择或过渡合并。返回的选择具有与此选择相同数量的组和相同的父元素。此选择中任何缺失(null)的元素将被指定 selection 中的对应元素填充(如果存在且不为 null)。(如果 other 选择有额外的组或父元素,它们将被忽略。)

此方法由 selection.join 内部使用,用于在绑定数据后合并 enterupdate 选择。你也可以显式地进行合并,但请注意,由于合并是基于元素索引的,所以你应使用能够保留索引的操作,例如使用 selection.select 而不是 selection.filter。例如:

🌐 This method is used internally by selection.join to merge the enter and update selections after binding data. You can also merge explicitly, although note that since merging is based on element index, you should use operations that preserve index, such as selection.select instead of selection.filter. For example:

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);

有关更多信息,请参阅 selection.data

🌐 See selection.data for more.

然而,这种方法并不打算用于连接任意选择:如果这个选择和指定的另一个选择在相同索引处都有(非空)元素,则合并中返回这个选择的元素,而另一个选择的元素将被忽略。

🌐 This method is not intended for concatenating arbitrary selections, however: if both this selection and the specified other selection have (non-null) elements at the same index, this selection’s element is returned in the merge and the other selection’s element is ignored.