选择集和数据的关系是 D3 最重要的基础,在【[入门 - 第 7 章](http://www.ourd3js.com/wordpress/?p=149)】时进行过些许讲解,对于要掌握好 D3 是远远不够的。故此开设一个新的分类,专门讨论选择集与数据的关系,包括数据绑定的使用和工作原理,update 、enter、exit 的原理和使用方法等,接下来一段时间里会有多篇此类文章。
D3 最大的特色就是能够将数据绑定到DOM上。使用select或selectAll选择元素之后,被选择的元素上是没有数据的。数据绑定就是使被选择元素里包含有数据。与此相关的函数有两个:
- datum():将指定数据赋值给被选择元素。
- data():将数据数组与选择集的元素结合。
上面的概念可能难以理解,不要着急,接下来依次剖析datum()和data(),来看看数据绑定是如何工作的,它们又有什么不同之处。虽然不理解原理也可直接使用这两个函数,但遇到意料之外的结果时往往会不知道如何调试,无从下手,因此大致知道其工作过程是必要的。
## datum()的工作过程
datum() 绑定数据的方法很简单,在 D3 中使用较少,但能帮助你理解数据 D3 是如何绑定数据的。请先看下面的代码:
~~~
<body>
<!-- 三个段落元素 -->
<p>Fire</p>
<p>Water</p>
<p>Wind</p>
<script>
//选择body中所有的p元素,选择集结果赋值给变量p
var p = d3.select("body").selectAll("p");
//绑定数值7到选择集上
p.datum(7);
//在控制台输出选择集
console.log(p);
</script>
</body>
~~~
这段代码中,使用datum()将数值7绑定到了选择集上,然后在控制台输出该选择集。在浏览器的控制台中,可以看到如图1所示的输出结果。其中包含有三个p元素,正是使用selectAll选择的三个段落,还可看到选择集的大小(length)、父节点(parentNode)等信息。
[![4-4-1](https://box.kancloud.cn/2016-08-17_57b4178545670.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-1.png)
图1
展开任意一个p元素,其各属性如图2所示。可以看到,经过绑定之后,多出了一个__data__属性,其数值7正是刚才绑定的数据。展开其他的p元素,会发现每一个元素中都多出了一个__data__,并且数值都是7。
[![4-4-2](https://box.kancloud.cn/2016-08-17_57b417855b35e.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-2.png)
图2
那么datum()的工作过程就再明了不过了,即对于选择集中的每一个元素,都为其增加一个__data__属性,属性值为datum(value)的参数value。此处的value并非一定要是number(数值)型,也可以是string(字符串)、boolean(布尔型)和object(对象),无论是什么类型,其工作过程都是给__data__赋值。如果使用undefined和null作为参数,则将不会创建__data__属性。下面来看看datum()的源代码:
~~~
d3_selectionPrototype.datum = function(value) {
return arguments.length
? this.property("__data__", value)
: this.property("__data__");
};
~~~
由上面的源代码可以知道,其实datum()是用D3的property()函数实现的:如果有参数value,则调用property给当前对象添加一个__data__属性,否则返回__data__属性值。下面来试验一下没有参数的情形:
~~~
var p = d3.select("body").selectAll("p");
p.datum(7);
console.log( p.datum() ); //在控制台输出被绑定的数据
~~~
这段代码将在控制台输出数字7,正是被绑定的数据。现有有一个问题,数据被绑定在选择集上后,该如何使用呢,或者说D3希望我们如何使用呢。下面举一个例子,使用被绑定的字符串,替换掉原字符串:
~~~
<body>
<p>Fire</p>
<p>Water</p>
<p>Wind</p>
<script>
var p = d3.select("body").selectAll("p");
p.datum("Thunder") //绑定字符串Thunder到选择集上
.text(function(d,i){ //替换内容
return d + " " + i;
});
</script>
</body>
~~~
这段代码中,使用datum()绑定了一个字符串Thunder到选择集上,然后调用text()替换字符串。text()用于设置或获取被选择元素的文本。text()的参数是一个无名函数function(d,i),这两个参数分别代表数据(datum)和索引(index)。这两个参数的名称也可以不使用d和i,但意义是不变的。在D3中,建议写成d和i。最后,在这个无名函数里返回了由d和i结合而成的字符串,中间加一空格。结果如图3所示,网页中的三个段落元素p的字符串被替换成:Thunder 0、Thunder 1、Thunder 2。
[![4-4-3](https://box.kancloud.cn/2016-08-17_57b417857bab5.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-3.png)
图3
由结果可知,无名函数的两个参数d和i,d表示被绑定的数据,i表示的索引号是从0开始的。在D3中使用被绑定的数据都是使用上述形式,即定义一个无名函数function(d,i),然后在函数的实现中使用d和i。D3还有一个特性,能使被绑定的数据传递给子元素。对前一段代码稍作修改:
~~~
p.datum("Thunder")
.append("span") //在每一个被选择元素后添加元素span
.text(function(d,i){
return " " + d;
});
~~~
结果如图4所示,各段落元素的末尾被添加了span元素,内容为Thunder。
[![4-4-4](https://box.kancloud.cn/2016-08-17_57b417858f0f2.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-4.png)
图4
下面使用console.log在控制台输出选择集p,输出结果如图5所示。可以看到,子元素span里也含有属性__data__,属性值也是字符串Thunder。于是可以得出一个结论:在被绑定数据的选择集中添加元素后,新元素也会具有被绑定数据。
[![4-4-5](https://box.kancloud.cn/2016-08-17_57b41785a6137.png)](http://www.ourd3js.com/wordpress/wp-content/uploads/2015/01/4-4-5.png)
图5
下一章讲述详细讲述 data() 的工作过程,谢谢阅读。
### 文档信息
- 版权声明:署名(BY)-非商业性(NC)-禁止演绎(ND)
- 发表日期:2015 年 1 月 12 日
- 更多内容:[OUR D3.JS - 数据可视化专题站](http://www.ourd3js.com/) 和 [CSDN个人博客](http://blog.csdn.net/lzhlzz)
- 备注:本文发表于 [OUR D3.JS](http://www.ourd3js.com/) ,转载请注明出处,谢谢