D3.js更新为转换

时间:2016-10-20 11:33:24

标签: javascript d3.js charts css-transitions d3v4

我使用以下代码更新使用d3v4创建的条形图:

d3.select("button.add")
        .on("click", function(){
            dataset.push(Math.floor(Math.random() * 30) + 5);
            xScale.domain(d3.range(dataset.length))
                    .rangeRound([0, w])
                    .padding(0.2);
            yScale.domain([0, d3.max(dataset)]);
            var bars = svg.selectAll("rect")
                            .data(dataset);

            bars.enter()
                .append("rect")
                .attr("class", "bar")
                .attr("x", w)
                .attr("y", function(d){return yScale(d);})
                .attr("width", xScale.bandwidth())
                .attr("height", function(d){return h - yScale(d)})
                .attr("fill", function(d){
                    return 'rgb('+d*3 + ',' + d*6 + ',' + d*9 + ')';
                });

            bars.transition()
                .delay(function(d, i){
                    return(i*1500) / dataset.length;
                })
                .duration(500)
                .ease(d3.easeLinear)
                .attr("x", function(d, i){ return xScale(i);})
                .attr("y", function(d) {return yScale(d);})
                .attr("width", xScale.bandwidth())
                .attr("height", function(d) {return h - yScale(d);});
        });

虽然添加了数据并且还创建了矩形元素,但是对于阵列中最新添加的元素,不会发生转换。只有在添加下一个元素并且不会发生该元素的转换时才会发生这种情况。

任何人都可以提供任何可能出错的提示吗?

提前致谢..

1 个答案:

答案 0 :(得分:6)

Since this is D3 v4, you'll have to merge the selections.

Every time you push one new value in your data array, your "enter" selection has one element. However, the transition doesn't happen for this new element, because you're calling the transition using bars and, unless you merge the selections, bars doesn't contain the "enter" selection.

So, your "enter" + "update" selections should be:

 bars.enter()// <-- this is just the "enter" selection
     .append("rect")
     .attr("class", "bar")
     .attr("x", w)
     .attr("y", function(d){return yScale(d);})
     .attr("width", xScale.bandwidth())
     .attr("height", function(d){return h - yScale(d)})
     .attr("fill", function(d){
         return 'rgb('+d*3 + ',' + d*6 + ',' + d*9 + ')';
      })
     .merge(bars)// <-- merge the selections: from now on, "enter" + "update"
     .transition()
     .delay(function(d, i){
         return(i*1500) / dataset.length;
     })
     .duration(500)
     .ease(d3.easeLinear)
     .attr("x", function(d, i){ return xScale(i);})
     .attr("y", function(d) {return yScale(d);})
     .attr("width", xScale.bandwidth())
     .attr("height", function(d) {return h - yScale(d);});

I know that this is "strange", but if you stop to think about it, the old D3 v3 way of dealing with the update selection is the wrong one, not this new v4 way. After all, bars doesn't contain the "enter" selection.

According to Mike Bostock:

D3 2.0 introduced a change to address [...] duplication: appending to the enter selection would now copy entering elements into the update selection. Thus, any operations applied to the update selection after appending to the enter selection would apply to both entering and updating elements, and duplicate code could be eliminated [...] This made usability worse. D3 4.0 removes the magic of enter.append.

(source: https://medium.com/@mbostock/what-makes-software-good-943557f8a488#.293tkrlfo, emphasis mine)