|
function randomizeData(n, y) { |
|
if (arguments.length < 2) y = 400; |
|
if (!arguments.length) n = 20; |
|
var i = 0; |
|
return d3.range(~~(Math.random()*n) + 1).map(function(d, i) { return { |
|
x: ++i, |
|
y: ~~(Math.random()*y) |
|
}}); |
|
} |
|
|
|
function update() { |
|
var data = randomizeData(20, Math.random()*100000); |
|
|
|
var margin = {top: 0, bottom: 20, left: 0, right: 0}, |
|
width = 400, |
|
height = 400, |
|
duration = 500, |
|
formatNumber = d3.format(',d'), |
|
brush = d3.svg.brush(); |
|
|
|
margin.left = formatNumber(d3.max(data, function(d) { return d.y; })).length * 14; |
|
var w = width - margin.left - margin.right, |
|
h = height - margin.top - margin.bottom; |
|
|
|
var x = d3.scale.ordinal() |
|
.rangeRoundBands([0, w], .1), |
|
y = d3.scale.linear() |
|
.range([h, 0]); |
|
|
|
y.domain([0, d3.max(data, function(d) { return d.y; })]); |
|
x.domain(data.map(function(d) { return d.x; })); |
|
|
|
var xAxis = d3.svg.axis() |
|
.scale(x) |
|
.orient('bottom'), |
|
yAxis = d3.svg.axis() |
|
.scale(y) |
|
.orient('left'), |
|
brush = d3.svg.brush() |
|
.x(x) |
|
.on('brushstart', brushstart) |
|
.on('brush', brushmove) |
|
.on('brushend', brushend); |
|
|
|
var svg = d3.select('#chart').selectAll('svg').data([data]), |
|
svgEnter = svg.enter().append('svg') |
|
.append('g') |
|
.attr('width', w) |
|
.attr('height', h) |
|
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') |
|
.classed('chart', true), |
|
chart = d3.select('.chart'); |
|
|
|
svgEnter.append('g') |
|
.classed('x axis', true) |
|
.attr('transform', 'translate(' + 0 + ',' + h + ')'); |
|
svgEnter.append('g') |
|
.classed('y axis', true) |
|
svgEnter.append('g').classed('barGroup', true); |
|
chart.selectAll('.brush').remove(); |
|
chart.selectAll('.selected').classed('selected', false); |
|
chart.append('g') |
|
.classed('brush', true) |
|
.call(brush) |
|
.selectAll('rect') |
|
.attr('height', h); |
|
|
|
bars = chart.select('.barGroup').selectAll('.bar').data(data); |
|
|
|
bars.enter() |
|
.append('rect') |
|
.classed('bar', true) |
|
.attr('x', w) // start here for object constancy |
|
.attr('width', x.rangeBand()) |
|
.attr('y', function(d, i) { return y(d.y); }) |
|
.attr('height', function(d, i) { return h - y(d.y); }); |
|
|
|
bars.transition() |
|
.duration(duration) |
|
.attr('width', x.rangeBand()) |
|
.attr('x', function(d, i) { return x(d.x); }) |
|
.attr('y', function(d, i) { return y(d.y); }) |
|
.attr('height', function(d, i) { return h - y(d.y); }); |
|
|
|
bars.exit() |
|
.transition() |
|
.duration(duration) |
|
.style('opacity', 0) |
|
.remove(); |
|
|
|
chart.select('.x.axis') |
|
.transition() |
|
.duration(duration) |
|
.call(xAxis); |
|
chart.select('.y.axis') |
|
.transition() |
|
.duration(duration) |
|
.call(yAxis); |
|
|
|
function brushstart() { |
|
chart.classed("selecting", true); |
|
} |
|
|
|
function brushmove() { |
|
var extent = d3.event.target.extent(); |
|
bars.classed("selected", function(d) { return extent[0] <= x(d.x) && x(d.x) + x.rangeBand() <= extent[1]; }); |
|
makeSum(); |
|
} |
|
|
|
function brushend() { |
|
chart.classed("selecting", !d3.event.target.empty()); |
|
} |
|
|
|
function makeSum() { |
|
var sumDiv = d3.select('#sum'), |
|
extent = brush.extent(), |
|
sum = 0; |
|
|
|
data.forEach(function(d) { |
|
if (extent[0] <= x(d.x) && x(d.x) + x.rangeBand() <= extent[1]) |
|
sum += d.y; |
|
}); |
|
sumDiv.text('TOTAL: ' + sum); |
|
} |
|
|
|
makeSum(); |
|
} |
|
|
|
update(); |