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));

 ...