<h2 class="bx--graph-header">Bar Graph</h2>
<div class="graph-container">
	<svg></svg>
	<div class="tooltip"></div>
</div>
body {
	padding: 1rem 3%;
}

.bx--graph-header {
	font-weight: 300;
	font-size: 24px;
}

.overlay {
	fill: #3d70b2;
	opacity: .1;
	display: none;
	pointer-events: none;
}

.line {
	stroke-width: 2;
	stroke: #FF00FF;
	fill: none;
	pointer-events: none;
}

.axis path {
	stroke: #5A6872;
}

.tick line {
	stroke: #5A6872;
}

.tick text {
	fill: #5A6872;
}

.graph-container {
	position: relative;
}

.tooltip {
	font-weight: 700;
	padding-left: 1rem 2rem;
	background-color: #fff;
	position: absolute;
	box-shadow: 0 4px 8px 0 rgba(0, 0, 0, .1); 
	border: 1px solid #DFE3E6;
	padding: .25rem .5rem;
	pointer-events: none;
	display: none;
	 
	&:after {
		content: '';
		top: 100%;
		left: 50%;
		transform: translateX(-50%);
		position: absolute;
		width: 0; 
		height: 0; 
		border-left: 5px solid transparent;
		border-right: 5px solid transparent;
		border-top: 5px solid #fff;
	}
}

.y path {
	display: none;
}

.label {
	font-size: 10px;
	font-weight: 700;
	fill: #5A6872;
	text-anchor: middle;
}
View Compiled
// Function to create random data in format: [date, amount]
function createData(num) {
	let data = [];
	for (var i = 0; i < num; i++) {
		const randomNum = Math.floor(Math.random() * 1000 + 1);
		let d = new Date();
		d.setDate(d.getDate() - (i * 30));
		data.push({
			date: d,
			amount: randomNum
		});
	}
	
	return data;
}

// Create + Format data
let data = createData(12).sort(function(a, b) { return a.date - b.date; });

// what are these and are they things that someone should edit
const margin = { top: 30, right: 20, bottom: 60, left: 65 };
const width = 800 - (margin.left + margin.right);
const height = 300 - (margin.top + margin.bottom);
const labelOffset = 50;
const axisOffset = 16;

// Set Time Format (JAN, FEB, etc..)
const timeFormat = d3.timeFormat('%b');

// Set the scales
const x = d3.scaleBand()
	.rangeRound([0, width])
	.domain(data.map((d) => d.date))
	.padding(0.5);

const y = d3.scaleLinear()
	.range([height, 0])
	.domain([0, d3.max(data, (d) => d.amount)]);

// // Set the axes
const xAxis = d3.axisBottom()
	.scale(x)
	.tickSize(0)
	.tickFormat(timeFormat)

const yAxis = d3.axisLeft()
	.ticks(4) 
	.tickSize(-width)
	.scale(y.nice());

// // Set up SVG with initial transform to avoid repeat positioning
const svg = d3.select('svg')
		.attr('class', 'graph')
		.attr('width', width + (margin.left + margin.right))
		.attr('height', height + (margin.top + margin.bottom))
		.append('g')
		.attr('class', 'group-container')
		.attr('transform', `translate(${margin.left}, ${margin.top})`)
		.attr('font-family', 'ibm-plex-sans');

// // Add Y axis
svg.append('g')
	.attr('class', 'axis y')
	.attr('stroke-dasharray', '4')
	.call(yAxis)
	.selectAll('text')
	.attr("x", -axisOffset)
	.attr('font-family', 'ibm-plex-sans');

// // Add Y axis label
const yLabel = svg.select('.y')
	.append('text')
	.text('USAGE ($)')
	.attr('class', 'label')
	.attr('transform', `translate(${-labelOffset}, ${height / 2}) rotate(-90)`)
	.attr('font-family', 'ibm-plex-sans');

// // Add X axis
svg.append('g')
	.attr('class', 'axis x')
	.attr('transform', `translate(0, ${height})`)
	.call(xAxis)
	.selectAll('text')
	.attr("y", axisOffset)
	.attr('font-family', 'ibm-plex-sans')

// // Add X axis label
const xLabel = svg.select('.x')
	.append('text')
	.text('MONTH')
	.attr('class', 'label')
	.attr('transform', `translate(${width / 2}, ${labelOffset})`)
	.attr('font-family', 'ibm-plex-sans');

svg.append('g')
	.attr('class', 'bar-container')
	.selectAll('rect')
	.data(data)
	.enter().append('rect')
	.attr('class', 'bar')
	.attr('x', (d) => x(d.date))
	.attr('y', (d) => height)
	.attr('height', 0)
	.attr('width', x.bandwidth())
	.attr('fill', '#00A78F')
	.transition()
	.duration(500)
	.delay((d, i) => i * 50)
	.attr('height', (d) => height - y(d.amount))
	.attr('y', (d) => y(d.amount));

// Select Tooltip
const tooltip = d3.select('.tooltip');
	
const bars = svg.selectAll('.bar')
	.on('mouseover', function(d) {	
		let color = d3.color('#00A78F').darker()
		d3.select(this)
			.attr('fill', color)
		tooltip
			.style('display', 'inherit')
			.text(`$${d.amount}`)
			.style('top', `${y(d.amount) - axisOffset}px`);
		
		let bandwidth = x.bandwidth();
		let tooltipWidth = tooltip.nodes()[0].getBoundingClientRect().width;
		let offset = (tooltipWidth - bandwidth) / 2;
		
		tooltip
			.style('left', `${x(d.date) + margin.left - offset}px`)
	})
	.on('mouseout', function(d) {
		d3.select(this)
			.transition()
			.duration(250)
			.attr('fill', '#00A78F')
		tooltip
			.style('display', 'none')
	})
View Compiled
Run Pen

External CSS

  1. https://unpkg.com/carbon-components@latest/css/carbon-components.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.3/d3.min.js