D3水平条形图动画不断

时间:2018-03-14 06:59:31

标签: d3.js

我正在尝试连续制作条形图的动画。我使用以下作为参考......

How to animate a horizontal D3 bar chart?

我看到动画每3秒出现一次,但是每个备用数据栏都会显示不正确的数据。无法弄清楚原因。

我的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

    body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        width: 960px;
        height: 500px;
        position: relative;
    }

    svg {
        width: 100%;
        height: 100%;
        position: center;
    }

    .toolTip {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        position: absolute;
        display: none;
        width: auto;
        height: auto;
        background: none repeat scroll 0 0 white;
        border: 0 none;
        border-radius: 8px 8px 8px 8px;
        box-shadow: -3px 3px 15px #888888;
        color: black;
        font: 12px sans-serif;
        padding: 5px;
        text-align: center;
    }

    text {
        font: 10px sans-serif;
        color: white;
    }
    <!-- text.value { -->
        font-size: 120%;
        fill: white;
    }

    .axisHorizontal path{
        fill: none;
    }

    .axisHorizontal .tick line {
        stroke-width: 1;
        stroke: rgba(0, 0, 0, 0.2);
    }

    .bar {
        fill: steelblue;
        fill-opacity: .9;
    }

</style>
<body>

<script src="http://d3js.org/d3.v3.min.js"></script>
<script>


    data = [
        {label:"Category 1", value:19},
        {label:"Category 2", value:5},
        {label:"Category 3", value:13},
        {label:"Category 4", value:17},
        {label:"Category 5", value:19},
        {label:"Category 6", value:27}
    ];


    var div = d3.select("body").append("div").attr("class", "toolTip");

    var axisMargin = 20,
            margin = 40,
            valueMargin = 4,
            width = parseInt(d3.select('body').style('width'), 10),
            height = parseInt(d3.select('body').style('height'), 10),
            barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
            barPadding = (height-axisMargin-margin*2)*0.6/data.length,
            data, bar, svg, scale, xAxis, labelWidth = 0;

    max = d3.max(data, function(d) { return d.value; });


    svg = d3.select('body')
            .append("svg")
            .attr("width", width)
            .attr("height", height);


    bar = svg.selectAll("g")

            //.exit()
            .data(data)
            .enter()
            .append("g")
            ;

    bar.attr("class", "bar")
            .attr("cx",0)
            .attr("transform", function(d, i) {
                return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
            });

    bar.append("text")
            .attr("class", "label")
            .attr("y", barHeight / 2)
            .attr("dy", ".35em") //vertical align middle
            .text(function(d){
                return d.label;
            }).each(function() {
        labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
    });

    scale = d3.scale.linear()
            .domain([0, max])
            .range([0, width - margin*2 - labelWidth]);

    xAxis = d3.svg.axis()
            .scale(scale)
            .tickSize(-height + 2*margin + axisMargin)
            .orient("bottom");


    bar.append("rect")

        .attr("transform", "translate("+labelWidth+", 0)")
        .attr("height", barHeight)
        .attr("width", 0)//this is the initial value
        .transition()
        .duration(1500)//time in ms
        //.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
        .attr("width", function(d){return scale(d.value);})

        ;
        //now, the final value
    function repeat() {

    var rect = bar.selectAll("rect")
                .remove()
                .data(data, function(d) { return d.value; })
                .enter()
                .append("rect")
                .attr("transform", "translate("+labelWidth+", 0)")
                .attr("height", barHeight)
                .attr("width", 0)//this is the initial value
                ;

        rect.transition()
            .duration(1500)
            .attr("width",0)
            //.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
            .attr("width", function(d){return scale(d.value);});

        //rect.exit().transition()
            //.duration(1500)
            //.attr("width", function(d){return scale(d.value);})
            //.remove();

        rect.exit().remove();
    }
setInterval(function(){repeat();},3000);

</script>
</body>

1 个答案:

答案 0 :(得分:1)

repeat功能中,您不需要每次重新创建条形图以重新运行转换。它可以简化为:

function repeat() {
  bar.select('rect')
      .attr('width',0) //<-- width 0
      .transition()
      .duration(1500)
      .attr("width", function(d){return scale(d.value);}); //<-- transition to full
}

运行代码:

&#13;
&#13;
<!DOCTYPE html>
<meta charset="utf-8">
<style>

    body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        width: 960px;
        height: 500px;
        position: relative;
    }

    svg {
        width: 100%;
        height: 100%;
        position: center;
    }

    .toolTip {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        position: absolute;
        display: none;
        width: auto;
        height: auto;
        background: none repeat scroll 0 0 white;
        border: 0 none;
        border-radius: 8px 8px 8px 8px;
        box-shadow: -3px 3px 15px #888888;
        color: black;
        font: 12px sans-serif;
        padding: 5px;
        text-align: center;
    }

    text {
        font: 10px sans-serif;
        color: white;
    }
    <!-- text.value { -->
        font-size: 120%;
        fill: white;
    }

    .axisHorizontal path{
        fill: none;
    }

    .axisHorizontal .tick line {
        stroke-width: 1;
        stroke: rgba(0, 0, 0, 0.2);
    }

    .bar {
        fill: steelblue;
        fill-opacity: .9;
    }

</style>
<body>

<script src="https://d3js.org/d3.v3.min.js"></script>
<script>


    data = [
        {label:"Category 1", value:19},
        {label:"Category 2", value:5},
        {label:"Category 3", value:13},
        {label:"Category 4", value:17},
        {label:"Category 5", value:19},
        {label:"Category 6", value:27}
    ];


    var div = d3.select("body").append("div").attr("class", "toolTip");

    var axisMargin = 20,
            margin = 40,
            valueMargin = 4,
            width = parseInt(d3.select('body').style('width'), 10),
            height = parseInt(d3.select('body').style('height'), 10),
            barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
            barPadding = (height-axisMargin-margin*2)*0.6/data.length,
            data, bar, svg, scale, xAxis, labelWidth = 0;

    max = d3.max(data, function(d) { return d.value; });


    svg = d3.select('body')
            .append("svg")
            .attr("width", width)
            .attr("height", height);


    bar = svg.selectAll("g")

            //.exit()
            .data(data)
            .enter()
            .append("g")
            ;

    bar.attr("class", "bar")
            .attr("cx",0)
            .attr("transform", function(d, i) {
                return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
            });

    bar.append("text")
            .attr("class", "label")
            .attr("y", barHeight / 2)
            .attr("dy", ".35em") //vertical align middle
            .text(function(d){
                return d.label;
            }).each(function() {
        labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
    });

    scale = d3.scale.linear()
            .domain([0, max])
            .range([0, width - margin*2 - labelWidth]);

    xAxis = d3.svg.axis()
            .scale(scale)
            .tickSize(-height + 2*margin + axisMargin)
            .orient("bottom");


    bar.append("rect")
        .attr("transform", "translate("+labelWidth+", 0)")
        .attr("height", barHeight)
        .attr("width", 0)//this is the initial value
        .transition()
        .duration(1500)//time in ms
        //.delay(function(d,i){ if(d.label == 'Category 6'){return 0}else{return i*350}})//a different delay for each bar
        .attr("width", function(d){return scale(d.value);})

        ;
        //now, the final value
    function repeat() {
      bar.select('rect')
          .attr('width',0)
          .transition()
          .duration(1500)
          .attr("width", function(d){return scale(d.value);});
    }

setInterval(function(){repeat();},3000);

</script>
</body>
&#13;
&#13;
&#13;