Skip to content

Instantly share code, notes, and snippets.

@ThomasBurleson
Last active October 9, 2019 15:13
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ThomasBurleson/c23f4a14917ad54551f9 to your computer and use it in GitHub Desktop.
Save ThomasBurleson/c23f4a14917ad54551f9 to your computer and use it in GitHub Desktop.
Reusable Chart component for D3 - using prototypes and factories
(function() {
// Based on article @ http://www.toptal.com/d3-js/towards-reusable-d3-js-charts
// Publish a factory method for Chart instances
// @usage:
// var runningChart = BarChart.instanceOf( {barPadding : 2 } );
// var weatherChart = BarChart.instanceOf()
// .fillColor('coral');
window.BarChart = {
instanceOf : function (options) {
// Publish instance
return new Chart(options);
}
};
// ***************************************************
// Define Chart class and methods
// ***************************************************
/**
* Define Chart Class
*/
function Chart(options) {
// Special draw `selection` method used by D3
this.render = drawSelection.bind(this);
this.options = initialize(options);
}
/**
* Build and assign prototype methods
*/
Chart.prototype = {
width : makeAccessor.call(this, this.options, 'width'),
height : makeAccessor.call(this, this.options, 'height'),
barPadding : makeAccessor.call(this, this.options, 'barPadding'),
fillColor : makeAccessor.call(this, this.options, 'fillColor')
};
// ***************************************************
// D3 Render method
// ***************************************************
/**
* Define the D3 callback to render bar chart within the specified
* selection DOMs
*/
function drawSelection(selection) {
selection.each(function(data) {
var barSpacing = this.height / data.length;
var barHeight = barSpacing - this.barPadding;
var maxValue = d3.max(data);
var widthScale = this.width / maxValue;
d3.select(this).append('svg')
.attr('height', this.height)
.attr('width', this.width)
.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('y', function(d, i) {
return i * barSpacing
})
.attr('height', barHeight)
.attr('x', 0)
.attr('width', function(d) {
return d * widthScale
})
.style('fill', this.fillColor);
});
}
// ***************************************************
// Utility methods
// ***************************************************
/**
* Build a chainable property accessor AND mutator function
*/
function makeAccessor(fields, key) {
return function() {
if (!arguments.length) return fields[key];
fields[key] = value;
return this;
}
}
/**
* Clone options data and initialize with defaults (if needed)
*/
function initialize(options) {
return extend({
width: 900,
height: 200,
barPadding: 1,
fillColor: 'steelblue'
},options);
}
/**
*
*/
function extend(dst) {
for (var i = 1, ii = arguments.length; i < ii; i++) {
var obj = arguments[i];
if (obj) {
var keys = Object.keys(obj);
for (var j = 0, jj = keys.length; j < jj; j++) {
var key = keys[j];
dst[key] = obj[key];
}
}
}
return dst;
}
})();
@aderito7
Copy link

How do you use? I am having a hard time hacking it

@gaiagilder
Copy link

What about version 4 of d3? Something is going wrong in line 27, the context is not passed to the function, maybe, i'm not javascript expert but because of this i'm very interested on how all this stuff can work, i always coded in the classic manner, Thanks

@ps23
Copy link

ps23 commented Jul 21, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment