Updating D3 column chart with different values and different data sizes

Posted by mbeasley on Stack Overflow See other posts from Stack Overflow or by mbeasley
Published on 2012-06-20T15:12:06Z Indexed on 2012/06/20 15:16 UTC
Read the original article Hit count: 239

Filed under:
|
|
|

Background

I am attempting to create a reusable chart object with D3.js. I have setup a chart() function that will produce a column chart. On a click event on any of the columns, the chart will update with a new random data array that will contain a random number of data points (i.e. the original chart could have 8 columns, but upon update, could have 20 columns or 4 columns).

Problem

Say I have 8 data points (and thus 8 columns) in my original dataset. When I update the chart with random data, the columns appropriately adjust their height to the new values - but new bars aren't added. Additionally, while the width of the columns appropriately adjust to accommodate the width of the container and the new number of data points, if that number of data points is less than the original set, then some of those columns from the original dataset will linger until the number of data points is greater than or equal than the original.

My end goal is to have new data dynamically added or old data outside of the range of the new data count dynamically removed.

I've created a jsfiddle of the behavior. You may have to click the columns a couple of times to see the behavior I'm describing. Additionally, I've pasted my code below.

Thanks in advance!

function chart(config) {

    // set default options
    var defaultOptions = {
        selector: '#chartZone',
        class: 'chart',
        id: null,
        data: [1,2,6,4, 2, 6, 7, 2],
        type: 'column', 
        width: 200,
        height: 200,
        callback: null,
        interpolate: 'monotone'
    };

    // fill in unspecified settings in the config with the defaults
    var settings = $.extend(defaultOptions, config);

    function my() { // generate chart with this function        

        var w = settings.width,
            h = settings.height,
            barPadding = 3,
            scale = 10,
            max = d3.max(settings.data);        

        var svg = d3.select(settings.selector) // create the main svg container
            .append("svg")
            .attr("width",w)
            .attr("height",h);

        var y = d3.scale.linear().range([h, 0]),
            yAxis = d3.svg.axis().scale(y).ticks(5).orient("left"),
            x = d3.scale.linear().range([w, 0]);

        y.domain([0, max]).nice();
        x.domain([0, settings.data.length - 1]).nice();        

        var rect = svg.selectAll("rect")
          .data(settings.data)
          .enter()
          .append("rect")
          .attr("x", function(d,i) {
            return i * (w / settings.data.length);
          })
          .attr("y", function(d) {
            return h - h * (d / max);
          })
          .attr("width", w / settings.data.length - barPadding)
          .attr("height", function(d) {
            return h * (d / max);
          })
          .attr("fill", "rgb(90,90,90)");

        svg.append("svg:g")
           .attr("class", "y axis")
           .attr("transform", "translate(-4,0)")
           .call(yAxis);        

        svg.on("click", function() {
            var newData = [], maxCap = Math.round(Math.random() * 100);

            for (var i = 0; i < Math.round(Math.random()*100); i++) {
                var newNumber = Math.random() * maxCap;
                newData.push(Math.round(newNumber));                
            }    

            newMax = d3.max(newData);

            y.domain([0, newMax]).nice();

            var t = svg.transition().duration(750);

            t.select(".y.axis").call(yAxis);

            rect.data(newData)
                 .transition().duration(750)
                 .attr("height", function(d) {
                    return h * (d / newMax);
                 })
                 .attr("x", function(d,i) {
                    return i * (w / newData.length);
                 })
                 .attr("width", w / newData.length - barPadding)
                 .attr("y", function(d) {
                    return h - h * (d / newMax);
                 });
            });
        }

    my();

    return my;

}

var myChart = chart();

© Stack Overflow or respective owner

Related posts about JavaScript

Related posts about charts