15
votes

I have to build d3 visualisations that work well both on tablets, Desktop displays, and in some cases very very large 4k+ high resolution cinema size displays.

So I'm trying to figure out what the trade off is between using SVG's 'viewBox' attribute with 'preserveaspectratio' vs having a resize function called to re-render on window resize events and use absolute values. Most examples, such as this blog entry (http://eyeseast.github.io/visible-data/2013/08/28/responsive-charts-with-d3/) suggest the latter in which I do something like this:

d3.select(window).on('resize', resize)

resize() {
// rerender each individual element with the new width+height of the parent node
d3.select('svg')
 .attr('width', newWidth)
//etc... and many lines of code depending upon how complex my visualisation is
}

However, why can't I just use SVG viewBox to let my SVG resize like so:

d3.select('svg')
  .attr( 'preserveAspectRatio',"xMinYMin meet")
  .attr("viewBox", "0 0 900 500")
  .attr('width', '100%')

I just make everything assuming that my width and height are 900x500px (or whatever), and leverage the fact that SVG is a vector format that takes care of all the fiddly details such as text sizes and margins. I'm struggling to see why so many people when giving examples of responsive or scalable visualisations using D3 favour a resize() function, and I'm very worried that I'm missing something if I go down the viewBox route.

Edit:

So in addition to what mef has said below, one thought is that with a viewBox I'm stuck with a particular aspect ratio. So I might want the height of the visualisation to stay fixed such as in the case of a line or bar chart, but it has it be responsive on its width. With a fixed aspect ratio this isn't possible as changes in width require changes in height. This case requires a resize() function that re-renders to fit to the new aspect ratio.

So although a viewBox with a fixed aspect ratio is significantly easier to implement, there are a lot of common cases that require greater control, which necessitates a resize() function and explains the community preference for the more complicated solution as a first and last resort. My use case probably favours the viewBox solution, which is slightly unusual when your requirement is responsiveness.

1

1 Answers

7
votes

I'd recommend using the following logic:

  • If your visualization is usable in the smallest screens you want to support with the viewBox technique, stick to that, no need to look further (lucky you :))
  • Otherwise: you may have the following problems when scaling down the visualizations:
    • there are too many details, that cannot be distinguished in smaller screens
    • the texts are too small and not readable in the smaller screens

Then you need to use javascript to adapt your visualization based on the screen size. This blog article which is serious about visualizations' responsiveness.

Oh, and don't forget to debounce your resize event listener.