简体   繁体   中英

How to transition between updated data of bar chart, in d3?

I'm trying to get an understanding of transitions in bar charts using D3. What I'm doing now is updating the chart between two different data sets. I have a transition included but it's starting from the the bottom of the axis rather than transitioning between the two. My goal is to have it transition between the two and later change the colors. I'm using this helpful example for understanding updated data (my snippet is not much different). Thank you for taking a look.

var bothData = [
{
    "year": "2014",
    "product": "Books & DVDs",
    "purchase": "0.5"
    },
    {
    "year": "2002",
    "product": "Books & DVDs",
    "purchase": "10"
    },
    {
    "year": "2014",
    "product": "Beer & Wine",
    "purchase": "7"
    },
    {
    "year": "2002",
    "product": "Beer & Wine",
    "purchase": "3"
    },
    {
    "year": "2014",
    "product": "Food",
    "purchase": "12"
    },
    {
    "year": "2002",
    "product": "Food",
    "purchase": "12"
    },
    {
    "year": "2014",
    "product": "Home Supplies",
    "purchase": "7"
    },
    {
    "year": "2002",
    "product": "Home Supplies",
    "purchase": "6"
    }
    ];

    var data2002 = [];
    var data2014 = [];

    for(var i = 0; i < bothData.length; i++){
        if(bothData[i]["year"] === "2002"){
            data2002.push(bothData[i]);
        }else{
            data2014.push(bothData[i]);
        }
    }

    function change(value){

        if(value === '2002'){
            update(data2002);
        }else if(value === '2014'){
            update(data2014);
        }
    }

    function update(data){
        xChart.domain(data.map(function(d){ return d.product; }) );
        yChart.domain( [0, d3.max(data, function(d){ return + d.purchase; })] );

        var barWidth = width / data.length;

        var bars = chart.selectAll(".bar")
                .remove()
                .exit()
                .data(data, function(d){ return d.purchase; })
                .enter()
                .append("rect")
                .attr("class", "bar")
                .attr("x", function(d, i){ return i * barWidth + 1 })
                .attr("y",500)
                .attr("height",0)
                .attr("width", barWidth - 5)
                .each(function(d){ 
                  if(d.year === "2014"){
                    d3.select(this)
                    .style('fill','#ea5454');
                  }else{
                    d3.select(this)
                    .style('fill','#4e97c4');
                  };
                });

        bars.transition()
          .duration(600)
          .ease(d3.easeLinear)
          .attr('y', function(d){ return yChart(d.purchase); })
          .attr('height', function(d){ return height - yChart(d.purchase); });

        chart.select('.y').call(yAxis);


        chart.select('.xAxis')
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis)
            .selectAll("text")
                .style("text-anchor", "end")
                .attr("dx", "-.8em")
                .attr("dy", ".15em")
                .attr("transform", function(d){
                    return "rotate(-65)";
                });

         }

    var margin = {top: 20, right: 20, bottom: 95, left: 50};
    var width = 400;
    var height = 500;

    var chart = d3.select(".chart")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var xChart = d3.scaleBand()
                .range([0, width]);

    var yChart = d3.scaleLinear()
                .range([height, 0]);

    var xAxis = d3.axisBottom(xChart);
    var yAxis = d3.axisLeft(yChart);


    chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)

    chart.append("g")
        .attr("class", "xAxis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", function(d){
            return "rotate(-65)";
                });

    chart.append("text")
        .attr("transform", "translate(-35," +  (height+margin.bottom)/2 + ") rotate(-90)")
        .text("Purchases");

    chart.append("text")
        .attr("transform", "translate(" + (width/2) + "," + (height + margin.bottom - 5) + ")")
        .text("Products");

    update(data2002);

You have the right idea...you want to achieve object constancy as described here by Mike Bostock. The key for your constancy should be the "product" from your data (not "purchase").

In your update function, define bars like this:

var bars = chart.selectAll(".bar")
            .data(data, function(d){ return d.product; })

then separate the .enter , .exit and .transition functions:

       bars.exit()
         .remove()
       bars.enter()
         ....
       bars.transition()

You have some strange stuff going on in your .enter function - like setting bar height to zero. So I modified your .enter and .transition functions like this:

          bars.enter()
            .append("rect")
            .attr("class", "bar")
            .attr("x", function(d, i){return i * barWidth + 1 })
            .attr("y",function(d){ return yChart(d.purchase); })
            .attr("height",function(d){ return height - yChart(d.purchase); })
            .attr("width", barWidth - 5)
            .attr('fill', function(d){ 
              if(d.year === "2014"){
                return'#ea5454'
              }else{
                return'#4e97c4'
              }

            })
    bars.transition()
      .duration(600)
      .ease(d3.easeLinear)
      .attr('y', function(d){ return yChart(d.purchase); })
      .attr('height', function(d){ return height - yChart(d.purchase); })
      .style('fill', function(d){
        if(d.year === "2014"){
          return '#ea5454'
        } else {
          return '#4e97c4'
        }
      })

Here is a working jsfiddle: https://jsfiddle.net/genestd/asoLph2w/
Note the buttons on top to achieve the transition.

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