d3 通用更新模式

d3 General Update Pattern

我只是模仿代码 d3 update pattern 尝试用更新的数据渲染一些矩形 这是我的代码。

            function update(data){
                var r = g.selectAll("rect").data(data,function(d){return (d)});

                r.exit().attr("class","exit").remove()

                r
                .attr("class","update")
                .attr("x",(d, i) =>{return i* (50+interval)})
                .attr("y", (d)=>{ return y(d)})
                .attr("width", "20px")
                .transition(t)
                .attr("height",( d => {  return  height-padding.top-padding.bottom-y(d);}))

                r.enter()
                .append("rect")
                .attr("width", "20px")
                .attr("class","new")
                .attr("x",(d, i) =>{  return i * (50+interval)})
                .attr("y", (d)=>{return y(d)})
                .attr("height",( d => {  return  height-padding.top-padding.bottom-y(d);}))

    
            }

然后我调用更新函数两次

            update([3,2,1,5,4,10,9,7,8,6])
            setTimeout(()=>{update([2,3,1,5,4,10,9,7,8,6])},1000)

预期:只有第一个和第二个rect会被重新渲染并设置class“new”,但实际上,所有的rect都会被设置class“new”。

Codepen

当数据是一组已识别对象时,enter/exit 模式有效。 替换此代码:

var r = g.selectAll("rect").data(data,function(d){return (d)});

与:

const _data = data.map((v,i) => ({id: i, value: v}));
const r = g.selectAll("rect").data(_data,d => d.id);

D3 将识别每个对象并相应地更新它,而不是替换为新对象。

看到它在 pen

中工作

更新: 如果要高亮显示值已更改的项目,可以将当前值保存在新添加项目的属性中:

r.enter()
  .append("rect")
  .attr('cur-value', d => d.value)
  ...

然后,在更新时,查询值并与数据中的值进行比较:

r.attr("class","update")
  ...
  .each(function(d) {
    const rect = d3.select(this);
    const prevValue = parseInt(rect.attr('cur-value'));
    rect.attr('cur-value', d.value);
    rect.style('fill', prevValue === d.value ? 'black' : 'red')
  });

您可以看到它在更新的笔中工作。