Thinking with Joins

Joins

在D3中, 我们是动态创建dom元素。一般可以使用append来创建单一元素:

const svg = d3.select("svg");
svg.append("circle").attrs({ cx: 5, cy: 5, r: 2.5 });

而如果要根据数组进行批量创建dom, 则需要以下写法:

const svg = d3.select("svg");
svg.selectAll('circle').data([20, 30, 40])
  .enter().append('circle')
  .attrs({ cx: d => d, cy: d => d, r: 5 });

而这里所有的疑惑, 都可使用下图进行解答:


image.png
  • 首先, 我们使用svg.selectAll('circle')产生一组空的选择器。
  • 选择器选择和数据进行绑定,这时候会产生三个操作:enter,update和exit。依据数据数据,enter依次对应数组中的每个元素,使用append产生update效果,在循环结束后,使用exit退出。

Key Function

一般情况下,我们使用data时候,要保证数组数据的顺序。如果是数组,则默认索引。如果数组的元素为一个字典,则需要提供一个key(因为字典是无序的)。
考虑以下的代码:

const otherData = [{value: 65}, {value: 35}, {value: 95}];
const svg = d3.select("svg");
svg.selectAll('circle').data(otherData)
  .enter().append('circle')
  .attrs({ cx: d => d.value, cy: d => d.value + 100, r: 5 });

这样会在界面上生成三个circle(图1)。虽然字典是无序的,但是不需要和已绘制的circle进行匹配,所以不需要key function.

1.png

在上述代码前面增加以下代码:

svg.selectAll('circle').data(data)
  .enter().append('circle')
  .attrs({ cx: d => d, cy: d => d, r: 5 });

这样会生成新的三个circle,图1的circle消失了。这是因为存在图1的代码情况下,图2的代码需要key function明确保证数组的顺序,否则无法绘图。
当我们加入:

.data(otherData, d => d.value)

后,图1图2均显示出来。

1.png

Enter, Update and Exit

Update: 提供数据,存在匹配的元素
Enter: 提供数据,不存在匹配的元素。
Exit: 提供元素,没有匹配的数据。

const data = [35, 65, 95];
const divs = d3.select('.chart').selectAll('p').data(data);
divs.enter().append('p').text(d => d);

const d1 = d3.select('.chart').selectAll('p').data([35, 65]);
d1.exit().remove();
  • 第一个divs,提供了update/enter的说明。
  • 而d1中,由于只提供了前两个数据,经过exit.remove后,会删除第三条数据。
  • 假设我们编写如下的代码(d1将做无用功),将不匹配的数据重新加入到页面中,则页面依旧保留三条数据:
    d1.exit().enter().append('p').text(d => d);

你可能感兴趣的:(Thinking with Joins)