简体   繁体   中英

D3.js update with transition

I'm using the following code to update a bar-chart created with 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);});
        });

Although data is added and rect elements are also created, the transition doesn't happen for the latest added element in the array. It only happens when the next element is added and the transition for that element does not happen.

Can anyone provide any hints as to what might be going wrong??

Thanks in advance..

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM