I have started building a charting library on top of d3js using javascript's inheritance. My goal is to develop reusable and fully customizable chart components. I read the article:
Towards Reusable Charts. Then, I went through the [source code of
nvd3.
NVD3 uses boiler plate code in each chart like: copying and pasting definitions for width, height, margin etc. BUT I would rather use inheritance to avoid such boiler plate code. I would like properties like: dimensions, axes and functions like zooming and event listeners to be reusable among all charts and customizable through any instance (object) of the chart.
Here is what my current library looks like. (It only supports bubble chart for now.)
var BaseChart = function(){
this.width = 200;
this.height = 200;//and others like: margin/ chart title
}
//XYChart inherits from BaseChart
var XYChart = function(){
//It contains members for axes, axis groups, labels, ticks, domains and ranges
//Example: One of the members it contains is "this.yAxis"
this.yAxis = d3.svg.axis().scale(this.scaleY)
.orient("left")
.ticks(this.yTickCnt)
.tickSize(-this.width);
}
//Extends XYChart and adds zooming
var ZoomableXYChart = function(){
this.zoom = function(){
this.svg.selectAll(this.dataShape)
.attr("transform", function(d, i) {
var translate = that.calculateTranslation(d);
return "translate(" + translate.x + "," + translate.y + ")";
});
}
}
//Extends zoomable XY chart and adds support for drawing shapes on data points
var BubbleChart = function(){
this.dataShape = "path";
this.drawChart = function()
{
this.prepareChart();//Attaches zooming, draws axes etc.
var that = this;
this.svg.selectAll(that.dataShape)
.data(that.data)
.enter()
.append(that.dataShape)
.attr("transform", function(d) {
return that.transformXYData(d);
})
.attr("d", symbolGenerator().size(100).type(function(d) {
return that.generateShape(d);
}))
.attr("fill", function(d) {
return that.generateColor(d);
})
.on("click", function(d) {
that.onClickListener(this, d);
})
}
}
I can create a chart in this way:
var chart = new BubbleChart();
chart.data = someData;
chart.width = 900;
chart.elementId = "#myChart";
chart.onClickListener = function(this,d){}
chart.drawChart();
This solution allows me to use common properties and functions across all charts. In addition to that, it allows any instance of any chart to override default properties and functions (like: onClickListener).
Do you see any limitations with such a solution? I haven't really seen javascript's inheritance used for d3.js and I wonder why? Is "chaining" that important? Using Mike Bostock's suggestions, how can we share functions like zooming across all XY charts? Isn't inheritance absolutely necessary to share functions and properties?