d3 数据绑定
d3的数据绑定是d3中最重要的知识点了,图像都需要数据支撑,所以掌握这个知识点非常重要。
d3官网提供了数据操作的多种API
我们要先用 d3.select 的方法选定DOM节点后,才能将数据绑定到 d3.select 回传的 selection 实体上,根据绑定的数据对元素进行增减。这两个方法都是一起出现的,没有单独使用 d3.data() 的情况. d3.selection().data()
1.data 方法
selection.data: 当数据跟 DOM 元素绑定时,会按照 index 的顺序将数据一一对应的绑定到DOM元素上。这时单一个 data 就会被存在匹配的单一个DOM元素 _data_ 这个属性中,并达成让元素与 DOM绑定在一起的效果;这里的data一般是可迭代的数组类型
<body>
<div>
<svg width="500" height="500" style="background-color: pink;">
<circle cx="50", cy="100" r="30" fill="blue" ></circle>
<circle cx="50", cy="100" r="30" fill="blue" ></circle>
<circle cx="50", cy="100" r="30" fill="blue" ></circle>
</svg>
<button>点我改变</button>
</div>
</body>
<script>
const data = d3.select("circle").data(["e"])
console.log(data);
const listData = Array.from(["e","c","h"])
const data1 = d3.selectAll("circle").data(listData);
console.log(data1);
</script>
2.datum 方法
官方文件上说的是,datum( ) 跟 data( )的不同在于,datum 无法合并数据、不能改数据的顺序,也不能去增减绑定的DOM API。
<body>
<div>
<svg width="500" height="500" style="background-color: pink;">
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
</svg>
<div class="test">111</div>
</div>
</body>
</html>
<script>
const listData = Array.from(["e","c","h","o"])
// const data1 = d3.selectAll("circle").data(listData);
// console.log(data1);
const data2 = d3.selectAll("circle").datum(listData);
console.log(data2);
</script>
| dom元素 | data | datum |
|---|---|---|
| circle one | e | [e,c,h,o] |
| circle two | c | [e,c,h,o] |
| circle three | h | [e,c,h,o] |
| 第四个不存在但是data存在 | o | 不存在 |
可以看到,data是根据元素的多少一一对应匹配到dom元素上,datum是直接全部绑定到dom元素上。
-
data使用场景
- 数据需要一一对应的绑定到一组dom元素上面
-
datum使用场景
- 把整组数据绑定到单独的一个 DOM 元素上
- 数据基本不会变动了,不需要对数据做增删改查处理
数据绑定原理
Enter / Update / Exit 状态
d3数据绑定,网络上一定会有这张图查询,接下来看看这个过程中主要做了什么
使用selection.data的时候,数据会跟DOM元素一一配对并绑定,因此也会出现两者的数量不匹配时,D3就把这些情况分成三种状态
- update : 如果数据跟DOM元素能够绑定,会放入update
- enter : 如果数据没有DOM元素能绑定,会放入 enter
- exit :如果没数据能跟被DOM元素绑定,会放入 exit
<body>
<div>
<svg width="500" height="500" style="background-color: pink;">
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
<circle cx="50" , cy="100" r="30" fill="blue"></circle>
</svg>
<div class="test">111</div>
</div>
</body>
</html>
<script>
const listData = Array.from(["e","c","h"])
const data1 = d3.selectAll("circle").data(listData);
console.log(data1);
</script>
无论是 _enter、_exit 或是 _groups,它们数量都一样是四个,对应的数据会放入update中
1.enter 数据比元素多
<body>
<div>
<svg width="500" height="500" style="background-color: pink;">
<circle cx="150" , cy="100" r="30" fill="blue"></circle>
<circle cx="60" , cy="100" r="20" fill="blue"></circle>
<circle cx="20" , cy="100" r="10" fill="blue"></circle>
</svg>
<p></p>
<p></p>
</div>
</body>
</html>
<script>
const enterData = ["e", "c", "h", "o"];
const eData = d3.selectAll('p').data(enterData)
console.log('eData', eData)
</script>
这里的data跟元素不一致,就可以看到对应的_enter 虽然是有四个,但是前两个是empty不存在后面的才是绑定到的data数据的元素
-
exit dom元素比data数据多
<body> <div> <svg width="500" height="500" style="background-color: pink;"> <circle cx="150" , cy="100" r="30" fill="blue"></circle> <circle cx="60" , cy="100" r="20" fill="blue"></circle> <circle cx="20" , cy="100" r="10" fill="blue"></circle> </svg> <p></p> <p></p> <p></p> <p></p> </div> </body> </html> <script> const exitData = ["e", "c",]; const eData = d3.selectAll('p').data(exitData) console.log('eData', eData) </script>_exit 的长度虽然是与元素个数一致,但是是有两个empty ,没有数据可以绑定上。
数据与dom元素不匹配的处理方法
主要是三个方法:
- selection.enter ( )
- selection.exit ( )
- selection.join ( )
1.enter()方法:这个方法会返还一个 enter selection,这个 enter selection 用来抓出缺失的DOM元素,以匹配多多余的数据,当取到缺少dom元素的数据后,需要使用append()方法将缺少的dom元素加进去,
<body>
<p></p>
</body>
</html>
<script>
const enterData = ["e","c","h"];
const eData = d3.selectAll('p')
.data(enterData)
.enter()
.append('p')
.text(d => d)
console.log(eData);
</script>
2.exit()方法: 将多余的dom元素删除
<body>
<p></p>
<p></p>
<p></p>
<p></p>
</body>
</html>
<script>
const enterData = ["e","c"];
const eData = d3.selectAll('p')
.data(enterData)
.exit()
.remove()
console.log(eData);
</script>
3.join()方法:它结合了 exter()、exit() 跟其他方法,让我们能更快速简单的增减元素,基本上都会用它,两外两个很少用了
<body>
<p></p>
<p></p>
<p></p>
<p></p>
</body>
</html>
<script>
const enterData = ["e","c"];
const eData = d3.selectAll('p')
.data(enterData)
.join()
.text(d => d)
// 这里的d就是取到的data的每一项数据
console.log(eData);
</script>
对data数据进行操作
const joinData = ['j', 'o', 'i', 'n']
d3.selectAll('.joinData')
.data(joinData)
.join()
.append('p')
.attr('class','.joinData')
.text(d => d); // 其实就是一个回调函数 .text(function(d){return d });
selection.text() 这个方法里面可以带入参数,如果带入的参数是一个方法,它代表的就是 每一个绑定数据的 selection 实体,而且会按照顺序回传个别 selection 绑定的 data 跟 index;