Question

I am a D3 beginner (with scratchy training wheels) seeking some help with Clipping. I would like to see the bars at both ends of my graph transitioning in and out neatly, like Mike Bostock's "A Bar Chart, Part 2" (from which I have grabbed some of his code and combined it with my own ). The stuff I am most confused with is in the comments. Apologies for the code slab, I am not sure what the root of the problem is. Many Thanks.

<!DOCTYPE html>
<html>
    <head>
    <title>Animated bar chart</title>
         <meta charset="UTF-8" />
    </head>

    <style>
    body {
        font-family: Verdana, sans-serif;
        font-size: 8pt;
        line-height: 12pt;
        background: #ffffff;
        color: #555555;
    }

    .axis path, .axis line {
        fill: none;
        stroke: #555555;
        shape-rendering: crispEdges;
    }

    .line {
        fill: none;
        stroke: orange;
        stroke-width: 1px;
    }

    .bar {
    fill: orange;
        shape-rendering: crispEdges;
    }

    .x.axis.path {
        display: none;
    }
    </style>

    <body>
    <h4>Animated bar chart</h4> 
    <script type="text/javascript" src="d3.v3.min.js"></script>

    <script>

    var t = -1;
    var v = 0;
    var data = d3.range(20).map(next); 

    function next () {
        return {
            time: ++t,
            value: v = Math.floor(Math.random()*20)
        };
    }

    setInterval(function () {
        data.shift();
        data.push(next());
        redraw();
    }, 1500);   

    var margin = {top: 20, right: 20, bottom: 30, left: 40},
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    var x = d3.scale.linear()
        .domain([0, 20])
        .range([0, width]);

    var barWidth = (width / 20) - 5;

    var y = d3.scale.linear()
        .domain([0, 20])
        .range([height, 0]);

    var xAxis = d3.svg.axis()
           .scale(x)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

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

    /* This definitiion by itself causes the first bar of chart to not appear
    var defs = svg.append("defs");
    defs.append("svg:clipPath") 
        .attr("id", "clip1");       

    This removes all the bars.  Not sure where this should go?
    var clip = svg.append("g")
        .attr("clip-path", "url(#clip1)")
        .append("svg:rect")
        .attr("width", width)
        .attr("height", height);
    */

    svg.selectAll("rect")
        .data(data)
        .enter().append("rect")
            .attr("class", "bar")
            .attr("x", function(d) { return x(d.time); })
            .attr("width", barWidth) 
            .attr("y", function(d) { return y(d.value); })
            .attr("height", function(d) { return (height - y(d.value)); }); 

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

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

    function redraw()
    {
    var rect = svg.selectAll("rect")
            .data(data, function(d) { return d.time; });

        // initialise entering bars and then do the transition
        rect.enter().append("rect")
            .attr("class", "bar")
            .attr("x", function(d, i) { return x(i + 1); })
            .attr("y", function(d) { return y(d.value); })
            .attr("width", barWidth)
            .attr("height", function(d) { return (height - y(d.value)); })
            .transition()
            .duration(1000)
            .attr("x", function(d, i) { return x(i); });

        // transition entering and updating bars
        rect.transition()
            .duration(1000)
            .attr("x", function(d, i) { return x(i); });

        // transition exiting bars
        rect.exit()
            .transition()
            .duration(1000)
            .attr("x", function(d, i) { return x(i - 1); })
            .remove();
    }
    </script>

</body>
</html>
Was it helpful?

Solution

Working example is located here: http://www.animatedcreations.net/d3/animatedBarChart_Slide.html. The bars transition in from the right and out to the left. The x axis updates in sync with the bars through a parent transition. Clipping was achieved by adding an additional SVG for the bars and the x axis.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top