data
with the actual data that you want to plot.labels
with the X labels for the data..html
extension.To understand the basics of creating a chart using D3 please read our article Creating bar charts using D3. Most of the code below has been explained in this article.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
svg {
border: 1px solid #ddd;
}
</style>
</head>
<body>
<div id="chart" style="width: 600px"></div>
<script>
// data and labels to plot
const data = [30, 10, 50, 20, 35, 45, 25];
const labels = ['1992', '1993', '1994', '1995', '1996', '1997', '1998'];
// maximum width of single bar so bar doesn't look like a box
const max_bar_width = 100;
// maximum height of the svg element
// this will include top and bottom offset
const svg_height = 600;
// bg color of bars
const bar_color = "#FFCB65";
// top and bottom margins
const top_offset = 50;
const bottom_offset = 50;
/**
* Darked/Lighten a color
* Copied from https://stackoverflow.com/a/13532993/10468888
*/
function shadeColor(color, percent) {
var R = parseInt(color.substring(1,3),16);
var G = parseInt(color.substring(3,5),16);
var B = parseInt(color.substring(5,7),16);
R = parseInt(R * (100 + percent) / 100);
G = parseInt(G * (100 + percent) / 100);
B = parseInt(B * (100 + percent) / 100);
R = (R<255)?R:255;
G = (G<255)?G:255;
B = (B<255)?B:255;
var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));
return "#"+RR+GG+BB;
}
// append svg
const svg = d3.select("#chart")
.append("svg")
.attr("fill", "red")
.attr("width", '100%')
.attr("height", svg_height);
// to make graph responsive calcuate we set width 100%
// here we calculate width in pixels
const svg_width = svg.node().getBoundingClientRect().width;
// decide bar width depending upon available space and no. of bars to plot
let bar_width = Math.round((svg_width - 60) / data.length);
if (bar_width > max_bar_width) {
bar_width = max_bar_width;
}
// spacing between two bars
// instead of having a fixed value we set it dynamically
const spacing = 0.15 * bar_width;
// to center align graph we move it from left to right
// this is applicable if there's any space left
let left_offset = Math.round((svg_width - bar_width*data.length)/2);
if (left_offset < 0) {
left_offset = 0;
}
// create scale
const scale = d3.scaleLinear()
.domain([0, Math.max(...data)])
.range([0, svg_height - top_offset - bottom_offset]);
// create scale for Y-Axis
// we could have used scale above but for Y-Axis we need domain reversed
const scale_y_axis = d3.scaleLinear()
.domain([Math.max(...data), 0])
.range([0, svg_height - top_offset - bottom_offset]);
// create tooltip element
const tooltip = d3.select("body")
.append("div")
.attr("class","d3-tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("padding", "15px")
.style("background", "rgba(0,0,0,0.6)")
.style("border-radius", "5px")
.style("color", "#fff")
.text("a simple tooltip");
// append rect
const rect = svg.selectAll("g")
.data(data)
.enter()
.append("rect")
.attr("fill", bar_color)
.attr("x", (d, i) => left_offset + bar_width * i)
.attr("y", d => svg_height - bottom_offset)
.attr("width", bar_width - spacing)
.on("mouseover", function(d, i) {
tooltip.html(`Data: ${d}`).style("visibility", "visible");
d3.select(this)
.attr("fill", shadeColor(bar_color, -15));
})
.on("mousemove", function(){
tooltip
.style("top", (event.pageY-10)+"px")
.style("left",(event.pageX+10)+"px");
})
.on("mouseout", function() {
tooltip.html(``).style("visibility", "hidden");
d3.select(this).attr("fill", bar_color);
});
// append text
svg.selectAll("g")
.data(data)
.enter()
.append("text")
.attr("dominant-baseline", "text-before-edge")
.attr("text-anchor", "middle")
.attr("fill", "#000000")
.attr("x", (d, i) => left_offset + bar_width * i + bar_width/2 - spacing/2)
.attr("y", svg_height - bottom_offset + 5)
.attr("style", "font-family:Verdana")
.text((d, i) => labels[i]);
// append X-Axis
svg.append("line")
.attr("stroke", "#000000")
.attr("stroke-width", 2)
.attr("x1", left_offset)
.attr("y1", svg_height - bottom_offset)
.attr("x2", bar_width * data.length + left_offset - spacing)
.attr("y2", svg_height - bottom_offset);
// appen Y-Axis
svg.append("g")
.attr("transform", "translate(0," + top_offset + ")")
.call(d3.axisRight(scale_y_axis));
window.onload = () => {
// set animation
rect.transition()
.ease(d3.easeLinear)
.duration(1000)
.attr("y", d => svg_height - bottom_offset - scale(d))
.attr("height", d => scale(d));
};
</script>
</body>
</html>