JSFiddle - React, Tailwind, and code Playground
by Max Sinev
HTML
<body>
<div id="stackedbars">
<svg id="stacked" width="600" height="500"></svg>
</div>
</body>
JavaScript
var BARS_ON_TOP = false;
var data = [
{
"year": "1991",
"color":"purple",
"value":12,
},
{
"year":"1991",
"color":"red",
"value":8,
},
{
"year": "1992",
"color":"red",
"value":20,
},
{
"year": "1993",
"color":"blue",
"value":9,
},
{
"year": "1993",
"color":"red",
"value":7,
},
{
"year": "1993",
"color":"purple",
"value":3,
},
];
var colors = [];
var dataSet = data.reduce((acc, d) => {
if (!~colors.indexOf(d.color)) colors.push(d.color);
if (!acc.length || acc[acc.length - 1].year !== d.year) {
var obj = { year: d.year };
obj[d.color] = d.value;
acc.push(obj);
} else {
acc[acc.length - 1][d.color] = d.value;
}
return acc;
}, []);
var svg = d3.select("#stacked"),
margin = {top: 20, right: 180, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.rangeRound([0, width])
.padding(0.3)
.align(0.3);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var z = d3.scaleOrdinal(colors);
var stack = d3.stack();
x.domain(dataSet.map((d) => d.year ));
y.domain(BARS_ON_TOP ? [25, 0] : [0, 25]);
z.domain(colors);
g.selectAll(".serie")
.data(stack.keys(colors)(dataSet))
.enter().append("g")
.attr("class", "serie")
.attr("fill", (d) => z(d.key))
.selectAll("rect")
.data((d) => d)
.enter().append("rect")
.attr("x", (d) => x(d.data.year))
.attr("y", (d) => nice(y(d[BARS_ON_TOP ? 0 : 1])))
.attr("height", (d) => nice(BARS_ON_TOP ? y(d[1]) - y(d[0]) : y(d[0]) - y(d[1])))
.attr("width", x.bandwidth());
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", BARS_ON_TOP ? "" : "translate(0," + height + ")")
.call( BARS_ON_TOP ? d3.axisTop(x) : d3.axisBottom(x));
...