forked from SpaceActuary's block: Bar Chart Transitions - Positive to Negative
forked from SpaceActuary's block: Trapezoid Charts
forked from SpaceActuary's block: Bar Chart Transitions - Positive to Negative
forked from SpaceActuary's block: Trapezoid Charts
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
margin: 0; | |
position: fixed; | |
top: 0; right: 0; bottom: 0; left: 0; | |
font-family: Arial, Helvetica, sans-serif | |
} | |
svg { | |
width: 100%; | |
height: 100%; | |
} | |
.axis { | |
/*stroke: lightgrey;*/ | |
shape-rendering: crispEdges; | |
} | |
.axis path { | |
fill: none; | |
stroke: lightgrey; | |
} | |
.x.axis line { | |
display: none; | |
} | |
.y.axis line { | |
fill: none; | |
stroke: lightgrey; | |
} | |
path.outline { | |
fill: none; | |
stroke: #000000; | |
stroke-width: 1.5; | |
} | |
line.total { | |
stroke-dasharray: 5,5; | |
} | |
</style> | |
<body> | |
<button onClick="randomize();">Randomize</button> | |
<button onClick="toggleVariance();">Toggle Variance-Only</button> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var years = d3.range(2007, 2016, 1).map(function(d){ return {year: d};}); | |
var varianceToggle = false; | |
var randomizeData = function(d){ | |
return { | |
year: d.year, | |
prior: (Math.random() * 6) + 3, | |
actual: (Math.random() * 5) + 4, | |
expected: (Math.random() * 5) + 4, | |
}; | |
}; | |
data = years.map(randomizeData); | |
var margin = {top: 30, right: 20, bottom: 50, left: 40}, | |
width = 960 - margin.left - margin.right; | |
height = 500 - margin.top - margin.bottom; | |
t = 1000, // transition time | |
b = width / data.length // block width | |
var x = d3.scale.ordinal() | |
.rangeRoundBands([0, width], .1) | |
.domain(data.map(function(d) { return d.year; })); | |
var y = d3.scale.linear() | |
.range([height, 0]) | |
.domain([0, d3.max(data, function(d){ | |
return d3.max([d.prior, d.actual, d.expected]) | |
})]) | |
.nice(); | |
var xAxis = d3.svg.axis().scale(x).orient("bottom"); | |
var yAxis = d3.svg.axis().scale(y).orient("left"); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
svg.append("g") | |
.attr("class", "y axis") | |
.attr("transform", "translate(0,0)") | |
.call(yAxis); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
svg.append("line") | |
.attr("class","total") | |
//This is the accessor function we talked about above | |
var lineFunction = d3.svg.line() | |
.x(function(d) { return d.x; }) | |
.y(function(d) { return d.y; }) | |
.interpolate("linear"); | |
var drawTrapezoid = function(d, i){ | |
var data; | |
if(varianceToggle){ | |
data = [ | |
{x: x(d.year), y: y(0)}, | |
{x: x(d.year), y: y(0)}, | |
{x: x(d.year) + x.rangeBand(), y: y(d.actual - d.expected)}, | |
{x: x(d.year) + x.rangeBand(), y: y(0)}, | |
{x: x(d.year), y: y(0)} | |
] | |
} else { | |
data = [ | |
{x: x(d.year), y: y(0) }, | |
{x: x(d.year), y: y(d.prior) }, | |
{x: x(d.year) + x.rangeBand(), y: y(d.actual) }, | |
{x: x(d.year) + x.rangeBand(), y: y(0) }, | |
{x: x(d.year), y: y(0) } | |
] | |
} | |
return lineFunction(data); | |
} | |
var drawVariance = function(d, i){ | |
var data; | |
if(varianceToggle){ | |
data = [ | |
{x: x(d.year), y: y(0)}, | |
{x: x(d.year) + x.rangeBand(), y: y(d.actual - d.expected)}, | |
{x: x(d.year) + x.rangeBand(), y: y(0)} | |
] | |
} else { | |
data = [ | |
{x: x(d.year), y: y(d.prior)}, | |
{x: x(d.year) + x.rangeBand(), y: y(d.actual)}, | |
{x: x(d.year) + x.rangeBand(), y: y(d.expected)} | |
] | |
} | |
return lineFunction(data); | |
} | |
var redraw = function(data){ | |
if (varianceToggle){ | |
// get the min / max variance | |
y.domain(d3.extent(data, function(d){ | |
return d.actual - d.expected; | |
})).nice();; | |
} else { | |
// domain = [0, largest value] | |
y.domain([0, d3.max(data, function(d){ | |
return d3.max([d.prior, d.actual, d.expected]) | |
})]).nice(); | |
} | |
var trapezoids = svg.selectAll("path.bars").data(data) | |
trapezoids.enter().append("path") | |
.attr("class","bars") | |
.attr("fill", "#c8c8c8"); | |
trapezoids.transition().duration(1000) | |
.attr("d", drawTrapezoid) | |
var variances = svg.selectAll("path.variance").data(data) | |
variances.enter().append("path") | |
.attr("class","variance"); | |
variances.transition().duration(1000) | |
.attr("d", drawVariance) | |
.attr("fill", function(d){ | |
return d.actual > d.expected ? "crimson" : "seagreen"; | |
}); | |
var outline = svg.selectAll("path.outline").data(data) | |
outline.enter().append("path") | |
.attr("class","outline"); | |
outline.transition().duration(1000) | |
.attr("d", drawTrapezoid); | |
// redraw y-axis | |
svg.selectAll("g.y.axis") | |
.transition() | |
.duration(1000) | |
.call(yAxis); | |
} | |
redraw(data); | |
var randomize = function(){ | |
data = data.map(randomizeData) | |
redraw(data); | |
} | |
var toggleVariance = function(){ | |
varianceToggle = !varianceToggle; | |
redraw(data); | |
} | |
</script> | |
</body> | |
</html> |