|
var graphs = graphs || {}; |
|
|
|
graphs.barChart = function module(){ |
|
|
|
var margin = {top: 20, right: 20, bottom: 30, left: 40}, |
|
width = 960, |
|
height = 500, |
|
gap = 2, |
|
data, |
|
chartWidth, chartHeight, |
|
xScale, yScale, |
|
xAxis, yAxis, |
|
svg, |
|
// extractors |
|
getLetter = function(d) { return d.letter; }, |
|
getFrequency = function(d) { return d.frequency; }; |
|
|
|
/** |
|
* This function creates the graph using the selection as container |
|
* @param {D3Selection} _selection A d3 selection that represents |
|
* the container(s) where the chart(s) will be rendered |
|
*/ |
|
function exports(_selection){ |
|
/* @param {object} _data The data to attach and generate the chart */ |
|
_selection.each(function(_data){ |
|
chartWidth = width - margin.left - margin.right; |
|
chartHeight = height - margin.top - margin.bottom; |
|
data = _data; |
|
|
|
buildScales(); |
|
buildAxis(); |
|
buildSVG(this); |
|
drawBars(); |
|
drawAxis(); |
|
}); |
|
} |
|
|
|
/** |
|
* Creates the d3 x and y axis, setting orientations |
|
* @private |
|
*/ |
|
function buildAxis(){ |
|
xAxis = d3.svg.axis() |
|
.scale(xScale) |
|
.orient('bottom'); |
|
|
|
yAxis = d3.svg.axis() |
|
.scale(yScale) |
|
.orient('left') |
|
.ticks(10, '%'); |
|
} |
|
|
|
/** |
|
* Builds containers for the chart, the axis and a wrapper for all of them |
|
* Also applies the Margin convention |
|
* @private |
|
*/ |
|
function buildContainerGroups(){ |
|
var container = svg.append('g') |
|
.classed('container-group', true) |
|
.attr({ |
|
transform: 'translate(' + margin.left + ',' + margin.top + ')' |
|
}); |
|
|
|
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); |
|
} |
|
|
|
/** |
|
* Creates the x and y scales of the graph |
|
* @private |
|
*/ |
|
function buildScales(){ |
|
xScale = d3.scale.ordinal() |
|
.domain(data.map(getLetter)) |
|
.rangeRoundBands([0, chartWidth], 0.1); |
|
|
|
yScale = d3.scale.linear() |
|
.domain([0, d3.max(data, getFrequency)]) |
|
.range([chartHeight, 0]); |
|
} |
|
|
|
/** |
|
* @param {HTMLElement} container DOM element that will work as the container of the graph |
|
* @private |
|
*/ |
|
function buildSVG(container){ |
|
if (!svg) { |
|
svg = d3.select(container) |
|
.append('svg') |
|
.classed('bar-chart', true); |
|
|
|
buildContainerGroups(); |
|
} |
|
svg.transition().attr({ |
|
width: width + margin.left + margin.right, |
|
height: height + margin.top + margin.bottom |
|
}); |
|
} |
|
|
|
/** |
|
* @description |
|
* Draws the x and y axis on the svg object within their |
|
* respective groups |
|
* @private |
|
*/ |
|
function drawAxis(){ |
|
svg.select('.x-axis-group.axis') |
|
.attr('transform', 'translate(0,' + chartHeight + ')') |
|
.call(xAxis); |
|
|
|
svg.select('.y-axis-group.axis') |
|
.call(yAxis); |
|
} |
|
|
|
/** |
|
* Draws the bar elements within the chart group |
|
* @private |
|
*/ |
|
function drawBars(){ |
|
var gapSize = xScale.rangeBand() / 100 * gap, |
|
barW = xScale.rangeBand() - gapSize, |
|
bars = svg.select('.chart-group').selectAll('.bar').data(data); |
|
|
|
// Enter |
|
bars.enter() |
|
.append('rect') |
|
.classed('bar', true) |
|
.attr({ |
|
width: barW, |
|
x: chartWidth, // Initially drawing the bars at the end of Y axis |
|
y: function(d) { return yScale(d.frequency); }, |
|
height: function(d) { return chartHeight - yScale(d.frequency); } |
|
}); |
|
|
|
// Update |
|
bars |
|
.attr({ |
|
width: barW, |
|
x: function(d) { return xScale(d.letter) + gapSize/2; }, |
|
y: function(d) { return yScale(d.frequency); }, |
|
height: function(d) { return chartHeight - yScale(d.frequency); } |
|
}); |
|
|
|
// Exit |
|
bars.exit() |
|
.style({ opacity: 0 }).remove(); |
|
} |
|
|
|
exports.margin = function(_x) { |
|
if (!arguments.length) return margin; |
|
margin = _x; |
|
return this; |
|
}; |
|
|
|
exports.width = function(_x) { |
|
if (!arguments.length) return width; |
|
width = _x; |
|
return this; |
|
}; |
|
|
|
exports.height = function(_x) { |
|
if (!arguments.length) return height; |
|
height = _x; |
|
return this; |
|
}; |
|
|
|
return exports; |
|
}; |