Skip to content

Instantly share code, notes, and snippets.

@nautilytics
Last active December 27, 2015 00:29
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 nautilytics/7238145 to your computer and use it in GitHub Desktop.
Save nautilytics/7238145 to your computer and use it in GitHub Desktop.
Waterfall Chart
(function () {
var yScale = d3.scale.linear();
var waterfallData = [];
var margin = 35;
var width = parseInt(d3.select('body').style("width")) - margin - margin,
height = parseInt(d3.select('body').style("height")) - margin - margin;
var xs = [
{label: "Tomatoes", value: 50},
{label: "Potatoes", value: 30},
{label: "Gas", value: 90},
{label: "Correction", value: -50},
{label: "Unplanned", value: 9},
{label: "Stuff", value: 20},
{label: "Other Stuff", value: 20},
{label: "Foo", value: 10}
];
var data = [];
var n = xs.length;
var xDelta = width / n;
var svg = d3.select("body").append("svg")
.attr("width", width + margin + margin)
.attr("height", height + margin + margin)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")");
// X-axis
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.05)
.domain(xs.map(function (d) {
return d.label;
}));
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
// Y-axis
var y = d3.scale.linear()
.range([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.ticks(4)
.orient("left");
// Trend line
var line = d3.svg.line()
.x(function (d, i) {
return i * xDelta + xDelta * .5 + margin / 2;
})
.y(function (d) {
return (d.value < 0) ? height - yScale(d.cumulativeSum - d.value) : height - yScale(d.cumulativeSum);
});
calculateScale();
calculateBars();
addBarLabels();
makeAxisLines();
function numberWithCommas(x) {
// Return the number formatted with commas
return (x > 1000) ? x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : x.toString();
}
function calculateScale() {
// Calculate scale of the y-axis for drawing waterfall bars
var max = 0, min = 0, cumSum = 0;
xs.forEach(function (d) {
cumSum += d.value;
if (cumSum < min) {
min = cumSum;
}
if (cumSum > max) {
max = cumSum;
}
data.push({value: d.value, cumulativeSum: cumSum});
});
y.domain([min, max]);
yScale.domain([min, max]).range([0, height]);
}
function calculateBars() {
// Calculate and add rectangles to the chart
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("class", function (d) {
return (d.value < 0) ? "negative" : "positive";
})
.attr("x", function (d, i) {
return i * xDelta + margin;
})
.attr("y", function (d, i) {
return (d.value < 0) ? height - yScale(d.cumulativeSum - d.value) : height - yScale(d.cumulativeSum);
})
.attr("width", function (d) {
return xDelta;
})
.attr("height", function (d) {
return yScale(Math.abs(d.value));
});
}
function addBarLabels() {
// Add labels to the rectangles
var barLabels = svg.append("g")
.selectAll('text')
.data(data)
.enter()
.append("text")
.attr("x", function (d, i) {
return i * xDelta + xDelta * .5 + margin / 2;
})
.attr("y", function (d, i) {
return (d.value < 0) ? height - yScale(d.cumulativeSum) + 25 : height - yScale(d.cumulativeSum);
})
.attr('dy', -5)
.text(function (d) {
return numberWithCommas(d.cumulativeSum.toFixed(0));
});
}
function makeAxisLines() {
// Draw x- and y- axis lines
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + margin + "," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.call(yAxis);
svg.append("path")
.datum(data)
.attr("class", "trend-line")
.attr("d", line);
}
})
()
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Waterfall Chart</title>
<style>
body, html {
height: 100%;
width: 95%;
padding: 0;
}
body {
background-image: url(logo4.png);
background-repeat: no-repeat;
background-position: 100% 100%;
}
.rect {
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
rect.positive {
fill: rgb(8, 37, 131);
}
rect.negative {
fill: rgb(255, 0, 0);
}
.trend-line {
fill: none;
stroke: rgb(0, 138, 0);
stroke-width: 1.5px;
stroke-dasharray: 10, 10;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="chart"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="d3.waterfall.js"></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment