How to Make d3 Charts Responsive

Responsive D3.js Charts

D3.js is an amazing javascript library that allows you to create beautiful charts and graphics from data from a variety of sources. I am in the process of shifting to using purely d3 for generating charts for this website, and one of the first obstacles that I had to overcome is making the charts where they would fit in the browser. Unfortunately, d3 charts will not be responsive even if the theme or framework that you are using is. The good news is that this is fairly simple to implement with just a little planning and a few lines of code.

Take a look at the code below. This is fairly basic code to begin a d3 bar chart.

var margin = {top: 20, right: 20, bottom: 30, left: 60},
width = 750 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

This code uses the standard margins convention that is very common in d3 now and after appending to the page will generate a svg graphic that is 750px wide and 500px tall. This is great until you load it on a screen that is smaller than 750px wide. Depending on how your framework is setup, your chart will either be cut off on the right side, or the user will have to scroll right and left to see the whole chart. Either way, this makes for a bad experience for the user.

Fortunately, we can use a little javascript to have the graphic size itself dynamically based on the size of its container. Let’s look at a quick example. D3 needs to be inside of an svg element, in order to render and to create that svg common convention is to use the d3.select method to select the parent element and use .append to append the svg to that div.

var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

Notice the .attr width uses the variable ‘width’ to define the width of the svg. To make the width value dynamic, we use the javascript .clientWidth element along with getElementById. This handy little piece of code will tell us the width of the parent container. Notice in the second line of code below, we create a new variable ‘ww’. This variable will hold the width of the div chart. Then we replace the hard-coded 750px with the variable in the next line.

var margin = {top: 20, right: 20, bottom: 30, left: 60},
ww = document.getElementById("chart").clientWidth,
width = ww - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

That’s all there is to it. Just be sure to append the svg to the same div that you are reading the width from. I have included a sample chart below so you can see this code in action. Be sure to view it on different devices and screen sizes, you will see that the chart always fits perfectly inside the window. You can also change the browser window size, just be sure to refresh the page after resizing.

4 comments

  1. “You can also change the browser window size, just be sure to refresh the page after resizing”

    I’m not sure I’d qualify this as “responsive”. One way to finish the job would be to bind a window resize to a new calculation function, so that the width and height and re-calculated on every resize.

Leave a Reply

Your email address will not be published. Required fields are marked *