Skip to content

Instantly share code, notes, and snippets.

@SpaceActuary
Created March 11, 2016 21:02
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 SpaceActuary/4d61f7211791b601b1e0 to your computer and use it in GitHub Desktop.
Save SpaceActuary/4d61f7211791b601b1e0 to your computer and use it in GitHub Desktop.
Trapezoid Charts 2 with Total
<!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 = true;
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){
var totalVariance = d3.sum(data, function(d){ return d.actual - d.expected; })
if (varianceToggle){
// get the min / max variance
y.domain(d3.extent(data, function(d){
return d.actual - d.expected;
}));
// make sure the total variance fits on the chart too
y.domain(
d3.extent(y.domain().concat([totalVariance]))
).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);
svg.selectAll("g.y.axis")
.transition()
.duration(1000)
.call(yAxis);
var total = svg.selectAll("line.total").data([1])
total.enter().append("line")
.attr("class","total")
.attr({
x1: 0,
x2: width
})
total.transition()
.duration(1000)
.attr("x1", 0)
.attr("x2", width)
.attr("y1", function(){
console.log("y1", toggleVariance ? y(totalVariance) : y(0));
return toggleVariance ? y(totalVariance) : y(0);
})
.attr("y2", function(){
console.log("y2", toggleVariance ? y(totalVariance) : y(0));
return toggleVariance ? y(totalVariance) : y(0);
})
.attr("stroke", totalVariance > 0 ? "crimson" : "seagreen")
.attr("stroke-width", toggleVariance ? 3 : 0);
}
redraw(data);
var randomize = function(){
data = data.map(randomizeData)
redraw(data);
}
var toggleVariance = function(){
varianceToggle = !varianceToggle;
redraw(data);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment