JSFiddle - React, Tailwind, and code Playground

by Cezar Pendarovski

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script>

CSS

svg {
  border: thin solid lightgray;
}

rect.project {
  opacity: 0.7;
  stroke: black;
  stroke-opacity: 0.5;
}

rect.frontend {
  fill: orange;
}

rect.operations {
  fill: blueviolet;
}

rect.devops {
  fill: bisque;
}

rect.backend {
  fill: salmon;
}

rect.database {
  fill: green;
}

rect.marketing {
  fill: cornsilk;
}

JavaScript

const projects = [
	{
  	'name': 'foo',
    'team': 'operations',
    'start_date': '2018-01-01',
    'end_date': '2019-12-31'
  },
	{
  	'name': 'bar',
    'team': 'operations',
    'start_date': '2017-01-01',
    'end_date': '2018-12-31'
  },
	{
  	'name': 'abc',
    'team': 'operations',
    'start_date': '2018-01-01',
    'end_date': '2018-08-31'
  },
	{
  	'name': 'xyz',
    'team': 'devops',
    'start_date': '2018-04-01',
    'end_date': '2020-12-31'
  },
	{
  	'name': 'wtf',
    'team': 'devops',
    'start_date': '2018-01-01',
    'end_date': '2019-09-30'
  },
	{
  	'name': 'qwerty',
    'team': 'frontend',
    'start_date': '2017-01-01',
    'end_date': '2019-01-31'
  },
	{
  	'name': 'azerty',
    'team': 'marketing',
    'start_date': '2016-01-01',
    'end_date': '2019-08-31'
  },
	{
  	'name': 'qwertz',
    'team': 'backend',
    'start_date': '2018-05-01',
    'end_date': '2019-12-31'
  },
	{
  	'name': 'mysql',
    'team': 'database',
    'start_date': '2015-01-01',
    'end_date': '2017-09-15'
  },
	{
  	'name': 'postgresql',
    'team': 'database',
    'start_date': '2016-01-01',
    'end_date': '2018-12-31'
  }
]

// Process data
projects.sort((a,b) => d3.ascending(a.start_date, b.start_date));

const data = d3.nest()
	.key(d => d.team)
  .entries(projects);

const flatData = d3.merge(data.map(d => d.values));

// Configure dimensions
const
	barHeight = 16,
  margin ={
  	top: 50,
    left: 100,
   	right: 20,
    bottom: 50
  },
  chart = {
  	width: 1000,
  	height: projects.length * barHeight
  },
  viewport = {
  	width: chart.width + margin.left + margin.right,
    height: chart.height + margin.top + margin.bottom
  },
  tickBleed = 5,
  labelPadding = 10
;

// Configure scales and axes
const xMin = d3.min(
	flatData,
  d => d3.isoParse(d.start_date)
);
const xMax = d3.max(
	flatData,
  d => d3.isoParse(d.end_date)
);

const xScale = d3.scaleTime()
	.range([0, chart.width])
	.domain([xMin, xMax])
;

const xAxis =...