Skip to content

Instantly share code, notes, and snippets.

@biovisualize
Created December 4, 2013 16:58
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 biovisualize/7791169 to your computer and use it in GitHub Desktop.
Save biovisualize/7791169 to your computer and use it in GitHub Desktop.
D3.js and Backbone
// Bar chart reusable component
/////////////////////////////////////
d3.custom = {};
d3.custom.barChart = function module() {
var config = {
margin: {top: 20, right: 20, bottom: 40, left: 40},
width: 500,
height: 500
};
var svg;
var dispatch = d3.dispatch('customHover');
function exports(_selection) {
_selection.each(function(_data) {
var chartW = config.width - config.margin.left - config.margin.right,
chartH = config.height - config.margin.top - config.margin.bottom;
var x1 = d3.scale.ordinal()
.domain(_data.map(function(d, i){ return i; }))
.rangeRoundBands([0, chartW], .1);
var y1 = d3.scale.linear()
.domain([0, d3.max(_data, function(d, i){ return d; })])
.range([chartH, 0]);
var xAxis = d3.svg.axis()
.scale(x1)
.orient('bottom');
var yAxis = d3.svg.axis()
.scale(y1)
.orient('left');
var barW = chartW / _data.length;
if(!svg) {
svg = d3.select(this)
.append('svg')
.classed('chart', true);
var container = svg.append('g').classed('container-group', true);
container.append('g').classed('chart-group', true);
container.append('g').classed('x-axis-group axis', true);
container.append('g').classed('y-axis-group axis', true);
}
svg.transition().attr({width: config.width, height: config.height})
svg.select('.container-group')
.attr({transform: 'translate(' + config.margin.left + ',' + config.margin.top + ')'});
svg.select('.x-axis-group.axis')
.attr({transform: 'translate(0,' + (chartH) + ')'})
.transition()
.call(xAxis);
svg.select('.y-axis-group.axis')
.transition()
.call(yAxis);
var barW = x1.rangeBand();
var bars = svg.select('.chart-group')
.selectAll('.bar')
.data(_data);
bars.enter().append('rect')
.classed('bar', true)
.attr({x: chartW,
width: barW,
y: function(d, i) { return y1(d); },
height: function(d, i) { return chartH - y1(d); }
})
.on('mouseover', dispatch.customHover);
bars.transition()
.attr({
width: barW,
x: function(d, i) { return x1(i); },
y: function(d, i) { return y1(d); },
height: function(d, i) { return chartH - y1(d); }
});
bars.exit().transition().style({opacity: 0}).remove();
});
}
exports.config = function(_newConfig) {
if (!arguments.length) return width;
for(var x in _newConfig) if(x in config) config[x] = _newConfig[x];
return this;
};
d3.rebind(exports, dispatch, 'on');
return exports;
};
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Backbone + D3.js Example</title>
<script type='text/javascript' src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script type='text/javascript' src="http://underscorejs.org/underscore-min.js"></script>
<script type='text/javascript' src="http://backbonejs.org/backbone-min.js"></script>
<script type='text/javascript' src="http://d3js.org/d3.v3.min.js"></script>
<script type='text/javascript' src="bar_chart.js"></script>
<style>
path.domain{
fill: none;
stroke: black;
}
rect{
fill: skyblue;
}
.tick line{
stroke: black;
}
</style>
</head>
<body>
<div class="control">
<button class="update-data">Update Data</button>
<button class="update-config">Update Config</button>
</div>
<div class="chart"></div>
<script>
// Bar chart view
/////////////////////////////////////
var BarChartView = Backbone.View.extend({
el: ".chart",
chart: null,
chartSelection: null,
initialize: function() {
_.bindAll(this, 'render', 'update');
this.model.bind('change:data', this.render);
this.model.bind('change:config', this.update);
chart = d3.custom.barChart();
chart.config(this.model.get('config'));
chart.on('customHover', function(d, i){ console.log('hover', d, i); });
this.render();
},
render: function() {
this.chartSelection = d3.select(this.el)
.datum(this.model.get('data'))
.call(chart);
},
update: function() {
this.chartSelection.call(chart.config(this.model.get('config')));
},
});
// Buttons view
/////////////////////////////////////
var ControlView = Backbone.View.extend({
el: ".control",
events: {
"click .update-data": "updateData",
"click .update-config": "updateConfig",
},
updateData: function() {
var that = this
var newData = d3.range(this._randomInt(10)).map(function(d, i){ return that._randomInt(100); });
this.model.set({data: newData});
},
updateConfig: function() {
var newConfig = {width: this._randomInt(600, 100)};
this.model.set({config: newConfig});
},
_randomInt: function(_maxSize, _minSize){
var minSize = _minSize || 1;
return ~~(Math.random() * (_maxSize - minSize)) + minSize;
}
});
// Bar chart data
/////////////////////////////////////
var BarChartData = Backbone.Model.extend({
defaults: {
data: [1, 2, 3, 4],
config: {height: 200, width: 400}
}
});
// Usage
/////////////////////////////////////
var barChartModel = new BarChartData();
var controlView = new ControlView({model: barChartModel});
var barChartView = new BarChartView({model: barChartModel})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment