Responsive embedded D3 SVG

The most D3 examples that I can find are not responsive embedded SVG. I guess the main reason for that is not to confuse the reader of a tutorial with stuff outside of D3. With the help of How to Scale SVG from Amelia Bellamy-Royds I would like to show on a minimal D3 example how to make the resulting SVG responsive.

A minimal D3 example

Let us start with the following minimal example that draws a white circle on a cyan rectangle.

<div id="wrapper"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var divWrapper = d3.select("#wrapper")
    .append("svg")
    .attr("width", 400)
    .attr("height", 200);

divWrapper.append('rect')
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "#cdebeb");

divWrapper.append("circle")
    .attr("cx", 200)
    .attr("cy", 100)
    .attr("r", 50)
    .attr("fill", "#ffffff");
</script>

The HTML and JavaScript code from above will result in the following embedded SVG that is not responsive.

Responsive embedded SVG

I will use Option 4: Use the padding-bottom Hack on a Container. There are just a few things we have to change on the example from above.

  • Do not set width and height attribute on the wrapper
  • Set viewBox attribute instead on the wrapper
  • Style the wrapper and the containing SVG with the padding-bottom Hack
<style>
#wrapper {
    position: relative;
    height: 0;
    width: 100%;
    padding: 0;
    /* padding-bottom will be overwritten by JavaScript later */
    padding-bottom: 100%;
}
#wrapper > svg {
    position: absolute;
    height: 100%;
    width: 100%;
    left: 0;
    top: 0;
}
</style>
<div id="wrapper"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 400,
    height = 200,
    wrapper = d3.select("#wrapper")
        .attr(
            "style",
            "padding-bottom: " + Math.ceil(height * 100 / width) + "%"
        )
        .append("svg")
        .attr("viewBox", "0 0 " + width + " " + height);

wrapper.append('rect')
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("fill", "#cdebeb");

wrapper.append("circle")
    .attr("cx", 200)
    .attr("cy", 100)
    .attr("r", 50)
    .attr("fill", "#ffffff");
</script>

The result should be a responsive embedded D3 SVG image.

Next Previous