Skip to content

Instantly share code, notes, and snippets.

@jfsiii
Created June 6, 2016 20:27

Revisions

  1. jfsiii created this gist Jun 6, 2016.
    6 changes: 6 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,6 @@
    Using a new updatable chart format. Update functions are made accessible to the caller, handing over chart controls
    with full functionality to the caller in a modular manner. Data binding is done with method chaining, like
    any other configuration variable, and can be changed after initialization. This allows for changes to be rendered
    in the context of chart history, leveraging D3's transitions and update logic.

    forked from <a href='http://bl.ocks.org/rcmoore38/'>rcmoore38</a>'s block: <a href='http://bl.ocks.org/rcmoore38/9f2908455355c0589619'>A New Pattern for Updatable D3.js Charts</a>
    135 changes: 135 additions & 0 deletions chart.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,135 @@
    function barChart() {

    // All options that should be accessible to caller
    var width = 500;
    var height = 300;
    var barPadding = 1;
    var fillColor = 'coral';
    var data = [];

    var updateWidth;
    var updateHeight;
    var updateFillColor;
    var updateData;

    function chart(selection){
    selection.each(function () {

    var barSpacing = height / data.length;
    var barHeight = barSpacing - barPadding;
    var maxValue = d3.max(data);
    var widthScale = width / maxValue;

    var dom = d3.select(this);
    var svg = dom.append('svg')
    .attr('class', 'bar-chart')
    .attr('height', height)
    .attr('width', width)
    .style('fill', fillColor);

    var bars = svg.selectAll('rect.display-bar')
    .data(data)
    .enter()
    .append('rect')
    .attr('class', 'display-bar')
    .attr('y', function (d, i) { return i * barSpacing; })
    .attr('height', barHeight)
    .attr('x', 0)
    .attr('width', function (d) { return d * widthScale; });


    // update functions
    updateWidth = function() {
    widthScale = width / maxValue;
    bars.transition().duration(1000).attr('width', function(d) { return d * widthScale; });
    svg.transition().duration(1000).attr('width', width);
    };

    updateHeight = function() {
    barSpacing = height / data.length;
    barHeight = barSpacing - barPadding;
    bars.transition().duration(1000).attr('y', function(d, i) { return i * barSpacing; })
    .attr('height', barHeight);
    svg.transition().duration(1000).attr('height', height);

    };

    updateFillColor = function() {
    svg.transition().duration(1000).style('fill', fillColor);
    };

    updateData = function() {
    barSpacing = height / data.length;
    barHeight = barSpacing - barPadding;
    maxValue = d3.max(data);
    widthScale = width / maxValue;

    var update = svg.selectAll('rect.display-bar')
    .data(data);

    update
    .transition()
    .duration(1000)
    .attr('y', function(d, i) { return i * barSpacing; })
    .attr('height', barHeight)
    .attr('x', 0)
    .attr('width', function(d) { return d * widthScale; });

    update.enter()
    .append('rect')
    .attr('class', 'display-bar')
    .attr('y', function(d, i) { return i * barSpacing; })
    .attr('height', barHeight)
    .attr('x', 0)
    .attr('width', 0)
    .style('opacity', 0)
    .transition()
    .duration(1000)
    .delay(function(d, i) { return (data.length - i) * 40; })
    .attr('width', function(d) { return d * widthScale; })
    .style('opacity', 1);

    update.exit()
    .transition()
    .duration(650)
    .delay(function(d, i) { return (data.length - i) * 20; })
    .style('opacity', 0)
    .attr('height', 0)
    .attr('x', 0)
    .attr('width', 0)
    .remove();
    }

    });
    }

    chart.width = function(value) {
    if (!arguments.length) return width;
    width = value;
    if (typeof updateWidth === 'function') updateWidth();
    return chart;
    };

    chart.height = function(value) {
    if (!arguments.length) return height;
    height = value;
    if (typeof updateHeight === 'function') updateHeight();
    return chart;
    };

    chart.fillColor = function(value) {
    if (!arguments.length) return fillColor;
    fillColor = value;
    if (typeof updateFillColor === 'function') updateFillColor();
    return chart;
    };

    chart.data = function(value) {
    if (!arguments.length) return data;
    data = value;
    if (typeof updateData === 'function') updateData();
    return chart;
    };

    return chart;
    }
    42 changes: 42 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Updatable Charts (4 of 4)</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="chart.js"></script>
    <style>
    div {
    padding: 20px 0 0 10px;
    }
    </style>
    </head>
    <body>
    <div id="updatableChart"></div>
    <script>

    var dataSet = [];
    var highTemperatures = dataSet[0] = [77, 71, 82, 87, 84, 78, 80, 84, 86, 72, 71, 68, 75, 73, 80, 85, 86, 80];
    var lowTemperatures = dataSet[1] = highTemperatures.map(function(d) { return d - Math.random() * 30});
    var milesRun = dataSet[2] = [2, 5, 4, 3, 1, 2, 1];
    var fillColors = ['coral', 'steelblue', 'teal'];

    var updatableChart = barChart().width(800).data(highTemperatures);

    d3.select('#updatableChart')
    .call(updatableChart);

    window.setTimeout(function() {
    updatableChart.height(450);
    }, 1000);

    var i = 1;
    window.setInterval(function() {
    updatableChart.data(dataSet[i]);
    updatableChart.fillColor(fillColors[i]);
    i = (i+1) % 3 ;
    }, 2500);

    </script>
    </body>
    </html>