d3js滚动可见性 - 条形图的系列动画

时间:2018-04-19 08:41:40

标签: javascript d3.js

enter image description here

我正在开发一个d3应用程序,我有兴趣采用以下jsfiddle - 和onload或一个动作 - 撤销动画,其中条形图逐个动画。

因此,第一个条形图为其高度,然后是第二个条形图等等。此外,动画的反转也很好 - 所以也许在滚动可见性上自动调用的东西?

http://jsfiddle.net/pg886/201/

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>

<div 
    class="barchart" 
    data-role="barchart" 
    data-width=300
    data-height=400 
    data-data="x"
    data-configurations=""
>
</div>

<style>
    .barchart{
        /*width:100%;
        border: 1px solid red;*/
    }

    .barchart svg{
        width:100%;
        /*border: 1px solid green;*/
    }

    .barchartg{

    }

    .barchart .axis path{
        fill: none;
        stroke: #000;
        shape-rendering: crispEdges;
    }

    .barchart .axis line {
        fill: none;
        stroke: none;
        shape-rendering: crispEdges;
    }

    .barchart .x.axis path {
        display: none;
    }

    .barchart .axis text{
        fill: #005a70;
    }

    .barchart.dark .axis text{
        fill: #ffffff;
    }
    .barchart.dark .axis path{  
        stroke: #ffffff;
    }

    .barchart .bar:hover {
        fill: #e9168a;
    }

</style>


<script>

    $(document).ready(function() {
        console.log("test")

        var $this = $(".barchart");

        var w = $this.data("width");
        var h = $this.data("height");
        var data = $this.data("data");

        var data = [{
            "label": "Apples",
            "value": 100
        },
        {
            "label": "Pears",
            "value": 120
        },
        {
            "label": "Bananas",
            "value": 20
        }];

        var configurations = $this.data("configurations");

        function colores_google(n) {
            var colores_g = ["#f7b363", "#448875", "#2b2d39", "#c12f39", "#f8dd2f", "#1b91dc"];
            return colores_g[n % colores_g.length];
        }

        //asess the margin bottom for the chart based on the max char label
        var charLabelCount = [];
        data.map(function(d) { 
            var labelStr =  d.label.toString();
            charLabelCount.push(labelStr.length); 
        })
        var maxChars = charLabelCount.reduce(function(a, b) {
            return Math.max(a, b);
        });

        var bottomMarg = 60;
        if(maxChars > 15){
            bottomMarg = 170;
        }
        //bottom margin calculation

        var margin = {top: 15, right: 20, bottom: bottomMarg, left: 40},
            width = w - margin.left - margin.right,
            height = h - margin.top - margin.bottom;

        var x = d3.scaleBand()
            .rangeRound([0, width]).padding(0.1);

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

        var xAxis = d3.axisBottom(x);
        var yAxis = d3.axisLeft(y);

        var svg = d3.select($this[0])
            .append("svg")
            .attr("width", w)
            .attr("height", h)
            .attr("viewBox", "0 0 "+w+" "+h)
            .attr("preserveAspectRatio", "xMidYMid meet")
          .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
            .attr("class", "barchartg");

        function sortBy(array,key){
            var sorted = array.sort(function(a, b) {
                return parseFloat(b[key]) - parseFloat(a[key]);
            });
            return sorted;
        }

        var sortedMax = 45;//45 as an initial value

        //if there is a configuration file - it acts as an overide -- this is so there could be just one chart -- or a set of charts next to each other
        if(configurations){
            //if its a comparison chart -- use a max value that will be shared amongst a stack of sibling charts
            if(configurations[0]["maxValue"]){
                sortedMax = configurations[0]["maxValue"] + 5;//add 5 value buffer
            }
        }
        else{
            //if its a stand alone chart - adjust the max val by this chart's own values
            sortedMax = sortBy(data, "value")[0]["value"] + 5;//add 5 value buffer
        }

        x.domain(data.map(function(d) { 
            return d.label; 
        }));

        y.domain([0, sortedMax]);

        svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis);

        svg.selectAll(".x.axis text")  
                .attr("transform", "rotate(-60) translate(-5,-5)")
                .style("text-anchor", "end");

        svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("");

        svg.selectAll(".bar")
          .data(data)
        .enter().append("rect")
          .attr("class", "bar")           
          .attr("fill", function(d, i) { 
            return colores_google(i);
          })
          .attr("x", function(d) { 
            return x(d.label); 
          })
          .attr("width", x.bandwidth())
          .attr("y", function(d) { 
            return y(d.value); 
          })
          .attr("height", function(d) { 
            return height - y(d.value); 
          });
    });

</script>

2 个答案:

答案 0 :(得分:3)

使用.transition()触发每个矩形的动画。

但是你必须以0和y为零开始每个rect,这样你就可以在动画中使用。

$(document).ready(function() {
  console.log("test")

  var $this = $(".barchart");

  var w = $this.data("width");
  var h = $this.data("height");
  var data = $this.data("data");

  var data = [{
      "label": "Apples",
      "value": 100
    },
    {
      "label": "Pears",
      "value": 120
    },
    {
      "label": "Bananas",
      "value": 20
    }
  ];

  var configurations = $this.data("configurations");

  function colores_google(n) {
    var colores_g = ["#f7b363", "#448875", "#2b2d39", "#c12f39", "#f8dd2f", "#1b91dc"];
    return colores_g[n % colores_g.length];
  }

  //asess the margin bottom for the chart based on the max char label
  var charLabelCount = [];
  data.map(function(d) {
    var labelStr = d.label.toString();
    charLabelCount.push(labelStr.length);
  })
  var maxChars = charLabelCount.reduce(function(a, b) {
    return Math.max(a, b);
  });

  var bottomMarg = 60;
  if (maxChars > 15) {
    bottomMarg = 170;
  }
  //bottom margin calculation

  var margin = {
      top: 15,
      right: 20,
      bottom: bottomMarg,
      left: 40
    },
    width = w - margin.left - margin.right,
    height = h - margin.top - margin.bottom;

  var x = d3.scaleBand()
    .rangeRound([0, width]).padding(0.1);

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

  var xAxis = d3.axisBottom(x);
  var yAxis = d3.axisLeft(y);

  var svg = d3.select($this[0])
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .attr("viewBox", "0 0 " + w + " " + h)
    .attr("preserveAspectRatio", "xMidYMid meet")
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .attr("class", "barchartg");

  function sortBy(array, key) {
    var sorted = array.sort(function(a, b) {
      return parseFloat(b[key]) - parseFloat(a[key]);
    });
    return sorted;
  }

  var sortedMax = 45; 
  
  if (configurations) {
  
    if (configurations[0]["maxValue"]) {
      sortedMax = configurations[0]["maxValue"] + 5; 
    }
  } else {
    
    sortedMax = sortBy(data, "value")[0]["value"] + 5; 
  }

  x.domain(data.map(function(d) {
    return d.label;
  }));

  y.domain([0, sortedMax]);

  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

  svg.selectAll(".x.axis text")
    .attr("transform", "rotate(-60) translate(-5,-5)")
    .style("text-anchor", "end");

  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("");

  svg.selectAll(".bar")
    .data(data)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("fill", function(d, i) {
      return colores_google(i);
    })
    .attr("x", function(d) {
      return x(d.label);
    })
    .attr("width", x.bandwidth())
    .attr("y", function(d) {
      return y(0);
    })
    .attr("height", function(d) {
      return 0
    });
    
    d3.selectAll("rect").transition()
    .duration(500)
    .delay(function(d,i){ return 500*i;})
    .attr("height",function(d){ return height - y(d.value);})
    .attr("y",function(d){return y(d.value);});
    
    setTimeout(function(){
    d3.selectAll("rect").transition()
    .duration(500)
    .delay(function(d,i){ return 600*(3-i);})
    .attr("height",function(d){ return 0;})
    .attr("y",function(d){return y(0);});
    },2000);
    
});
.barchart {
  /*width:100%;
		border: 1px solid red;*/
}

.barchart svg {
  width: 100%;
  /*border: 1px solid green;*/
}

.barchartg {}

.barchart .axis path {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.barchart .axis line {
  fill: none;
  stroke: none;
  shape-rendering: crispEdges;
}

.barchart .x.axis path {
  display: none;
}

.barchart .axis text {
  fill: #005a70;
}

.barchart.dark .axis text {
  fill: #ffffff;
}

.barchart.dark .axis path {
  stroke: #ffffff;
}

.barchart .bar:hover {
  fill: #e9168a;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>



<div class="barchart" data-role="barchart" data-width=300 data-height=400 data-data="x" data-configurations="">
</div>

答案 1 :(得分:1)

你需要为每个栏添加过渡,同时根据你的意愿生成并延迟转换。代码为。

.transition()
  .delay(function (d,i){ return i * 300;})        
  .duration(250)

代码块的更新代码如下

svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar") 
  .transition()
  .delay(function (d,i){ return i * 300;})        
  .duration(250)
      .attr("fill", function(d, i) { 
        return colores_google(i);
      })
      .attr("x", function(d) { 
        return x(d.label); 
      })
      .attr("width", x.bandwidth())
      .attr("y", function(d) { 
        return y(d.value); 
      })
      .attr("height", function(d) { 
        return height - y(d.value); 
      })