Create a responsive bar chart with D3.js
12 Apr 2016In this tutorial you’ll learn how to create a responsive bar chart using D3.
Note: The example uses D3 v3.5.15, but you can use the SVG code for any D3 version
The final graph looks like this:
Creating a responsive D3 graph
D3 creates graphs as SVGs.
You create a root <svg>
element and append it to a container <div>
:
const svg = d3
.select('div#chart-container')
.append('svg')
The <svg>
is the element you need to make responsive. As long as the <svg>
is responsive, the content you add with D3 will scale automatically.
You can make the <svg>
responsive by adding a preserveAspectRatio
attribute of xMinYMin meet
, and a viewbox
attribute of 0 0 WIDTH HEIGHT
. Where WIDTH
and HEIGHT
are the width and height of your graph.
The HTML would look like this:
<div id="chart-container">
<svg
id="chart"
preserveAspectRatio="xMinYMin meet"
viewBox="0 0 800 440"
>
<!-- -->
</svg>
</div>
You can set the <svg>
attributes dynamically with D3:
svg
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr(
'viewBox',
'0 0 ' +
(width + margin.left + margin.right) +
' ' +
(height + margin.top + margin.bottom)
)
That’s the basic responsive SVG done. The only thing left is to create the graph itself.
You can see the full code for the graph below:
const letters = ['A', 'B', 'C', 'D']
const numbers = [20, 60, 30, 20]
const height = 400
const width = 700
const barWidth = width / numbers.length
const margin = { left: 50, top: 10, right: 50, bottom: 30 }
const getRatio = side => (margin[side] / width) * 100 + '%'
const marginRatio = {
left: getRatio('left'),
top: getRatio('top'),
right: getRatio('right'),
bottom: getRatio('bottom')
}
const svg = d3
.select('div#chart-container')
.append('svg')
.style(
'padding',
marginRatio.top +
' ' +
marginRatio.right +
' ' +
marginRatio.bottom +
' ' +
marginRatio.left +
' '
)
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr(
'viewBox',
'0 0 ' +
(width + margin.left + margin.right) +
' ' +
(height + margin.top + margin.bottom)
)
const x = d3.scale
.ordinal()
.domain(letters)
.rangeRoundBands([0, width], 0.1, 0.1)
const xAxis = d3.svg
.axis()
.scale(x)
.orient('bottom')
const y = d3.scale
.linear()
.domain([d3.max(numbers), 0])
.range([0, height])
const yAxis = d3.svg
.axis()
.scale(y)
.orient('left')
const bar = svg
.selectAll('g')
.data(numbers)
.enter()
.append('g')
.attr('transform', (_, i) => 'translate(' + i * barWidth + ', 0)')
svg
.append('g')
.attr('class', 'x axis')
.call(xAxis)
.attr('transform', 'translate(0,' + height + ')')
svg
.append('g')
.attr('class', 'y axis')
.call(yAxis)
bar
.append('rect')
.attr('class', 'bar')
.attr('width', barWidth - 1)
.attr('y', d => y(d))
.attr('height', d => height - y(d))
And there you have it—a responsive bar chart with D3.
If you have any questions, leave a comment. Or get in touch @EddYerbugh