|
function barChart() { |
|
|
|
// All options that should be accessible to caller |
|
var width = 500; |
|
var height = 300; |
|
var barPadding = 1; |
|
var fillColor = 'coral'; |
|
var data = []; |
|
|
|
var updateWidth; |
|
var updateHeight; |
|
var updateFillColor; |
|
var updateData; |
|
|
|
function chart(selection){ |
|
selection.each(function () { |
|
|
|
var barSpacing = height / data.length; |
|
var barHeight = barSpacing - barPadding; |
|
var maxValue = d3.max(data); |
|
var widthScale = width / maxValue; |
|
|
|
var dom = d3.select(this); |
|
var svg = dom.append('svg') |
|
.attr('class', 'bar-chart') |
|
.attr('height', height) |
|
.attr('width', width) |
|
.style('fill', fillColor); |
|
|
|
var bars = svg.selectAll('rect.display-bar') |
|
.data(data) |
|
.enter() |
|
.append('rect') |
|
.attr('class', 'display-bar') |
|
.attr('y', function (d, i) { return i * barSpacing; }) |
|
.attr('height', barHeight) |
|
.attr('x', 0) |
|
.attr('width', function (d) { return d * widthScale; }); |
|
|
|
|
|
// update functions |
|
updateWidth = function() { |
|
widthScale = width / maxValue; |
|
bars.transition().duration(1000).attr('width', function(d) { return d * widthScale; }); |
|
svg.transition().duration(1000).attr('width', width); |
|
}; |
|
|
|
updateHeight = function() { |
|
barSpacing = height / data.length; |
|
barHeight = barSpacing - barPadding; |
|
bars.transition().duration(1000).attr('y', function(d, i) { return i * barSpacing; }) |
|
.attr('height', barHeight); |
|
svg.transition().duration(1000).attr('height', height); |
|
|
|
}; |
|
|
|
updateFillColor = function() { |
|
svg.transition().duration(1000).style('fill', fillColor); |
|
}; |
|
|
|
updateData = function() { |
|
barSpacing = height / data.length; |
|
barHeight = barSpacing - barPadding; |
|
maxValue = d3.max(data); |
|
widthScale = width / maxValue; |
|
|
|
var update = svg.selectAll('rect.display-bar') |
|
.data(data); |
|
|
|
update |
|
.transition() |
|
.duration(1000) |
|
.attr('y', function(d, i) { return i * barSpacing; }) |
|
.attr('height', barHeight) |
|
.attr('x', 0) |
|
.attr('width', function(d) { return d * widthScale; }); |
|
|
|
update.enter() |
|
.append('rect') |
|
.attr('class', 'display-bar') |
|
.attr('y', function(d, i) { return i * barSpacing; }) |
|
.attr('height', barHeight) |
|
.attr('x', 0) |
|
.attr('width', 0) |
|
.style('opacity', 0) |
|
.transition() |
|
.duration(1000) |
|
.delay(function(d, i) { return (data.length - i) * 40; }) |
|
.attr('width', function(d) { return d * widthScale; }) |
|
.style('opacity', 1); |
|
|
|
update.exit() |
|
.transition() |
|
.duration(650) |
|
.delay(function(d, i) { return (data.length - i) * 20; }) |
|
.style('opacity', 0) |
|
.attr('height', 0) |
|
.attr('x', 0) |
|
.attr('width', 0) |
|
.remove(); |
|
} |
|
|
|
}); |
|
} |
|
|
|
chart.width = function(value) { |
|
if (!arguments.length) return width; |
|
width = value; |
|
if (typeof updateWidth === 'function') updateWidth(); |
|
return chart; |
|
}; |
|
|
|
chart.height = function(value) { |
|
if (!arguments.length) return height; |
|
height = value; |
|
if (typeof updateHeight === 'function') updateHeight(); |
|
return chart; |
|
}; |
|
|
|
chart.fillColor = function(value) { |
|
if (!arguments.length) return fillColor; |
|
fillColor = value; |
|
if (typeof updateFillColor === 'function') updateFillColor(); |
|
return chart; |
|
}; |
|
|
|
chart.data = function(value) { |
|
if (!arguments.length) return data; |
|
data = value; |
|
if (typeof updateData === 'function') updateData(); |
|
return chart; |
|
}; |
|
|
|
return chart; |
|
} |
Don't you think your update functions (e.g.
updateWidth) will work only if there is one item in yourselection? And if there are more than one items, only the last item will get updated?