Integrating an interactive chart into a responsive web page

Before we begin

This post is intended to show how to add interactive Scalable Vector Graphic (SVG) content to a web page that you might write from scratch by yourself; a web page that doesn’t involve WordPress or any other content management system.

However, this blog does use WordPress (unlike the rest of the site) so there are one or two other minor details that need to be taken care of to get the results shown. For the purpose of clarity and brevity, these are ignored (if anyone is really interested I might write a follow up post).

To follow along you will probably need at least a basic understanding of HTML, CSS and SVG and, for later sections, knowledge of JavaScript and d3.js.

Introduction

I’m a fairly new convert to the world of smartphones but converted I am. I now get frustrated when accessing pages on my phone and they don’t work too well. So I’ve tried to make this site as easy to read and get around on phones (and tablets) as on a desktop computer (but do please let me know if you have any issues). That includes, as far as possible, the interactive data displays. This post discusses some of the basics – focusing on how to simply resize an SVG based on changes in dimensions of a container div. Other similar solutions are out there, this is just a record of how I often do things. I intend to follow this post up with another post on some of the finer details of responsive chart creation with d3. The MobileVis project from bocoup has some more nice resources on such things.

Getting a chart on to a page

A pre-created SVG (one that isn’t constructed entirely using JavaScript commands) can be added to an HTML5 page in a number of ways, including:

  1. Using an image tag;
  2. Using an object tag;
  3. Directly pasting the pre-generated code in to the html;
  4. Using a PHP command like require_once.

Option 1 is great if you just want a static vector image but doesn’t work with any form of scripting. Option 3 works but isn’t a good choice for easy maintenance. I used to prefer option 2 but it can lead to some weird behaviour (particularly in Safari) when returning to the page using the browser’s back button. Consequently I usually opt for option 4, which is essentially a more maintainable version of option 3. Since nearly all the popular browsers now support inline SVG  and the pages of this website already utilise PHP, this works fairly well:

Note: if your SVG file has an XML declaration at the top then you’ll have to delete that.

I recently discovered that d3 also offers the possibility of importing SVG using the d3.xml command. This provides another solution and avoids PHP use, which could be desirable for some.

Of course, if you purely use d3 (or another JavaScript library) to generate your SVG from scratch then the above discussion is moot.

Using CSS to make an SVG responsive

When the SVG is pre-generated I usually use CSS to make it responsive, but it’s not as easy as you might expect. Setting a defined width and maximum width and setting height to auto as you might do with a normal image:

…gets you mixed results, even if you delete any width and height attributes in the svg tag. In Firefox and Opera this seems to work perfectly if the viewBox parameter is properly defined but in Chrome and Safari you’re likely to end up with lots of undesirable whitespace above and below the graphic.

The solution to this I got from demosthenes.info, specifically the post titled – appropriately enough – Make SVG Responsive. This example works perfectly for me and I don’t think there is much point in repeating it verbatim (and I’d feel like I had stolen something if I did), so I suggest reading it at this point (it won’t take more than a few minutes) and then heading back here.

Putting it all together, we take an SVG, alter its svg tag as described in the article and add it to the page inside a div (preferably) using method 4, above. Then we add the CSS for the svg-container and svg-content classes from the article (adjusting the padding-bottom value) and stick any script needed for interactive features in the web page’s head section (or before the closing body tag if you prefer). We get…

USA 1 UK 2 Germany 3 Canada 4 Australia 5 Russia 6 France 7 South Africa 8 Japan 9 Argentina 10 Italy 11 Mexico 12 China 13 Saudi Arabia 14 Brazil 15 Turkey 16 South Korea 17 India 18 Indonesia 19 USA 1 UK 10 Germany 8 Canada 4 Australia 3 Russia 5 France 13 South Africa 9 Japan 7 Argentina 14 Italy 11 Mexico 16 China 12 Saudi Arabia 2 Brazil 17 Turkey 15 South Korea 6 India 19 Indonesia 18 G-20 countries ranked by annual carbon dioxide emissions per capita 1960 1965 1970 1975 1980 1985 1990 1995 2000 2005 2010 1960 1965 1970 1975 1980 1985 1990 1995 2000 2005 2010 Year OECD country Non-OECD country

You can test that the above is responsive by resizing the browser or, if you’re on a mobile or tablet, changing the orientation of the device. You can also interact by clicking/tapping on any of the country names or clicking the chart’s title. More details about this chart are available here and here.

Using JavaScript to make an SVG responsive

The alternative is to use JavaScript. This is my preferred way to do things when the SVG is being generated in JavaScript anyway. All of this I do with d3 (sometimes with a little assistance from jQuery). With the d3 library already added to the page, the start of the SVG creation code might look something like this for a page that is not responsive:

This code places a 900 pixels wide, 485 pixels high SVG inside a div element with the class “svg-container2”.

For a responsive SVG the first 15 lines can stay the same. The remainder doesn’t need that much work:

The viewBox attribute (defined on the new line 16) essentially tells the browser which set of dimensions to pretend to be using inside the SVG. By adding this property to the SVG (line 20) we’re basically telling the browser to scale everything consistently internally regardless of the external dimensions. We’re then free to rescale the SVG using the height and width attributes, keeping only the aspect ratio constant.

Lines 22 to 30 define, using a closure, a function for determining and setting the SVG’s height and width based on the current width of the container div element. The use of a closure simply means the aspect ratio is only calculated once. If closures make you uneasy you can define the aspect ratio outside the function altogether or replace lines 22-30 with the following:

Line 32 sets the current height and width the figure should be while line 33 tells the browser to update this every time the browser window is resized. A browser resize does not necessarily mean a div resize so one could, if desired, check for a difference between the “newWidth” value and the current width attribute of the SVG prior to updating the latter, but this doesn’t seem particularly necessary. This code also assumes that the container div will only change size when the window resizes. This has always been a safe assumption for me, but there may be instances where it isn’t.

Adding a little CSS to style a few elements:

the div to hold the SVG:

and the actual code to draw the chart contents (here a slightly simplified version of my Newcastle United Points Tracker) and we have:

You can read a random match report for each game of this season by clicking/tapping on the corresponding circle.

With slight modifications to the above one can, of course, use JavaScript to control the pre-generated SVG or CSS to control the script-generated SVG. In the interest of brevity I will refrain from doing so here.

Leave a Reply

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