How to Resize an SVG When the Window is Resized in d3.js

Data Tutorial

Scalable Vector Graphics, or SVG, is a markup language that describes and generates two-dimensional vector graphics, primarily for the web and viewed on modern browsers.

When developing with SVG, it can often be difficult to scale SVG objects when the containing frame or even the entire browser window changes size. The reason SVG doesn’t inherently scale well when compared to, say, an image, is that SVG is in fact not an image at all – SVG is an object.

Think of it this way: Images have specific dimensions (width and height) and thus when a browser displays them or is asked to resize them, it can just automatically adjust the number of pixels in either the x or y axis. Your computer then recalculates which pixels along those axes should be which colors to best represent that now resized image, discarding the least important pixels in the process.

Since SVG isn’t an image and thus can be drawn (rendered) at any pixel size, the browser doesn’t inherently associate a width or height unless you explicitly give it one; nor will it be able to resize the SVG even if the parent container changes size.

The viewBox and preserveAspectRatio Attributes

To begin down the road to dynamically resizing SVGs, we need to understand two basic attributes: viewBox and preserveAspectRatio.

The viewBox attribute is an essential component to SVG that actually makes them scalable. It defines the aspect ratio, the inner scaling of object lengths and coordinates, and the axis coordinates (x and y) for where the SVG should originate.

For example, if we want our SVG to have a zero x and zero y origin while having a width and height of 300 units, we’d define the attribute as follows:

<svg viewBox="0 0 300 300"></svg>

The preserveAspectRatio attribute, as the name implies, determines if the SVG should scale when the aspect ratio defined in viewBox doesn’t match the ratio in the parent container. Due to this relationship, preserveAspectRatio requires that the viewBox attribute also be set to function.

In most cases, this attribute will be defined like so:

<svg preserveAspectRatio="xMidYMid meet"></svg>

This forces uniform scaling for both the x and y, aligning the midpoint of the SVG object with the midpoint of the container element.

Scaling d3.js Dynamic Charts

With an understanding of how SVG scaling operates to some degree, we can look at how to scale an SVG chart from a dynamic library like d3.js.

There are a few rules that need to be implemented for this to function: + The SVG object needs to be wrapped in a div or similar container. + The SVG object cannot have width or height attributes. + The viewBox and preserveAspectRatio attributes need to be properly defined. + The SVG object needs a secondary CSS class/style to ensure absolute positioning.

To accomplish these goals, we create a basic div with the class svg-container and the id container in our HTML:

<div id="container" class="svg-container">
</div>

Our CSS is two classes, one for the aforementioned container and the other to define the CSS of the SVG object itself:

.svg-container {
    display: inline-block;
    position: relative;
    width: 100%;
    padding-bottom: 100%;
    vertical-align: top;
    overflow: hidden;
}
.svg-content {
    display: inline-block;
    position: absolute;
    top: 0;
    left: 0;
}

Finally, for the JavaScript where we use d3.js to create our SVG chart object, we need to ensure the SVG is contained within the container div. The SVG also needs the two vital attributes and should also have the svg-content class. We accomplish this with the following JavaScript code:

var svg = d3.select("div#container")
  .append("svg")
  .attr("preserveAspectRatio", "xMinYMin meet")
  .attr("viewBox", "0 0 300 300")
  .classed("svg-content", true);

The rest of the JavaScript that is used to create the d3.js chart and work with the data isn’t very relevant. The only importantance is if you are defining a width and height of the chart initially somewhere, copy those values as the third and forth arguments of the viewBox SVG attribute. As mentioned, the SVG object cannot have the width and height attributes actually defined (since that’s handled dynamically via CSS), but the viewBox needs proper values as discussed above.

With that complete, the d3.js SVG chart should now scale dynamically with the container (or full screen window).