Skip to content

Instantly share code, notes, and snippets.

@kongondo
Forked from robert-moore/README.md
Created February 18, 2018 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kongondo/8aa7cc63eb99db5648fc40782575803c to your computer and use it in GitHub Desktop.
Save kongondo/8aa7cc63eb99db5648fc40782575803c to your computer and use it in GitHub Desktop.
A New Pattern for Updatable D3.js Charts

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.

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;
}
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment