d3—select.data数据操作原理

194 阅读3分钟

d3 数据绑定

d3的数据绑定是d3中最重要的知识点了,图像都需要数据支撑,所以掌握这个知识点非常重要。

d3官网提供了数据操作的多种API

1.png

我们要先用 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.png

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>

3.png

dom元素datadatum
circle onee[e,c,h,o]
circle twoc[e,c,h,o]
circle threeh[e,c,h,o]
第四个不存在但是data存在o不存在

可以看到,data是根据元素的多少一一对应匹配到dom元素上,datum是直接全部绑定到dom元素上。

  • data使用场景

    1. 数据需要一一对应的绑定到一组dom元素上面
  • datum使用场景

    1. 把整组数据绑定到单独的一个 DOM 元素上
    2. 数据基本不会变动了,不需要对数据做增删改查处理

数据绑定原理

Enter / Update / Exit 状态

5.png

d3数据绑定,网络上一定会有这张图查询,接下来看看这个过程中主要做了什么

使用selection.data的时候,数据会跟DOM元素一一配对并绑定,因此也会出现两者的数量不匹配时,D3就把这些情况分成三种状态

  1. update : 如果数据跟DOM元素能够绑定,会放入update
  2. enter : 如果数据没有DOM元素能绑定,会放入 enter
  3. 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中

6.png

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数据的元素

7.png

  1. 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 ,没有数据可以绑定上。

8.png

数据与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>

9.png

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>

10.png

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>

11.png

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