D3.js 核心概念——数据绑定(一)选择器工作原理

883 阅读3分钟

原文(持续更新):datavis-note.benbinbin.com/article/d3/…


系列文章可以查看《数据可视化》专栏


参考:

本文主要介绍 Selections 模块

D3 框架的核心是使用数据驱动 DOM 元素,所以在项目中经常需要将数据与视觉元素(一般是SVG 元素)进行绑定 join,主要使用 d3-selection 模块提供的各种方法实现,然后数据会添加到 DOM 元素的 __data__ 属性中,这样特定的数据就和特定的元素「结合」在一起了(即使清空了选择集,再次重新选择元素,也可以读取到原来绑定的数据)。


通过调用 D3 提供的多种选择器,如 d3.selection() 选中页面的根元素,可以得到相应的选择集。它类似于数组,但并不是直接包含选中的元素,而是先包含了一系列的分组 _groups,再在每个分组中包含相应的一系列匹配条件而被选中的元素。

Snipaste_2022-01-21_12-36-29.png

💡 而且选择集还具有属性 _parents 用以记录各分组的父节点 parentNode 信息。

💡 此外在选择集的原型 prototype 上还有一系列类似数组的方法,方便我们对选择集进行操作,例如 selection.sort() 对选择集的元素进行排序。

以下是 d3.selection() 返回的选择集的结构示意图

Snipaste_2022-01-21_12-36-59.png

可以在控制台打印出该选择集:

  • 属性 _groups 中具有一个分组,其中只有一个元素 <html> 即页面的根元素
  • 属性 _parents 包含了各组相应的父节点,由于唯一的分组(具有一个元素是根节点 <html>)没有父节点,所以是空 null
  • 原型 prototype 列出了多种选择集特有的方法,它们一般会返回所操作的选择集,便于进行链式调用

selection-prototype.png

一般情况下,选择集中都只有一个分组,除非进行了嵌套选择 Nested Selections 操作,即使用了 selection.selectAll() 方法生成的选择集。

例如使用 d3.selectAll('td') 选中页面的所有表格单元格(假设页面只有一个表格,且该表格是一个 4x4 表格),以下图示为选择集的结构,该选择集只有一个分组,由于使用方法 d3.selectAll() 所以该分组的父节点是页面的根元素 <html> 然后该分组内包含了 16 个 <td> 元素

flatten-select.png

如果采用嵌套选择方式,先选中表格的各行,然后对选择集进行「二次选择」,再分别选中各行的单元格 d3.selectAll('tr').selectAll('td') 以下图示为选择集的结构,该选择集有四个分组,每个分组的父节点都是相应的行,每个分组内的元素都是相应行的单元格

nest-select.png

使用以 selection.selectAll 进行嵌套选择时,分组会变动。它会为原选择集中的每个元素创建一个分组,然后将各元素被选中的后代元素作为该分组的元素。还可以进行多次嵌套选择,例如再进一步选择所有单元格内的 <span> 元素。

🎉 可以在该网页查看动图演示,看看嵌套选择时分组的变化过程,更容易理解

💡 选择集的方法一般都适用于具有单个或多个分组的情况,而且调用选择集方法一般都相同(除了 selection.data(data) 当选择集只有一个分组时,入参是一个数组;当选择集具有多个分组时,需要传递的是一个返回数组的函数),D3 在这些方法内部会自动分组依次执行。