JSFiddle - React, Tailwind, and code Playground
by gdicerbo
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
CSS
.axis text {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
JavaScript
function barStack(seriesData) {
var l = seriesData[0].length
while (l--) {
var posBase = 0; // positive base
var negBase = 0; // negative base
seriesData.forEach(function(d) {
d = d[l]
d.size = Math.abs(d.y)
if (d.y < 0) {
d.y0 = negBase
negBase -= d.size
} else
{
d.y0 = posBase = posBase + d.size
}
})
}
seriesData.extent = d3.extent(
d3.merge(
d3.merge(
seriesData.map(function(e) {
return e.map(function(f) { return [f.y0,f.y0-f.size] })
})
)
)
)
}
/* Here is an example */
// each series is an array of objects
// our data is in turn an array of those series arrays
// which is to say
// an array of arrays of objects
var data = [
[ {y:-14202756}, {y:0}, {y:0}, {y:0} ],
[ {y:0}, {y:2242378}, {y:4168212}, {y:4244142} ],
[ {y:0}, {y:-515070}, {y:-704541}, {y:-720288} ]
]
var h = 500;
var w = 500;
var margin = 20;
var color = d3.scale.category10();
var x = d3.scale.ordinal()
.domain(['2018', '2019', '2020', '2021'])
.rangeRoundBands([ margin, w - margin ], .1)
var y = d3.scale.linear()
.range([h-margin,0+margin]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(6, 0);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
barStack(data);
y.domain(data.extent);
svg = d3.select("body")
.append("svg")
.attr("height", h)
.attr("width", w)
svg.selectAll(".series")
.data(data)
.enter()
.append("g")
.classed("series", true)
.style("fill", function(d,i) { return color(i) })
.style("opacity", 0.8)
.selectAll("rect")
.data(Object)
.enter()
.append("rect")
.attr("x", function(d, i) { return x(x.domain()[i]) })
.attr("y", function(d) { return y(d.y0) })
.attr("height", function(d) { return y(0) - y(d.size) })
.attr("width", x.rangeBand())
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition =...