Last Updated: February 25, 2016
· javier_toledo

Creating an interactive SVG map

RaphaelJs is an awesome library for vectorial drawing on a website, specially suited for interactive graphics. In a recent project I created a RaphaelJs interactive map for spanish provinces which you can test here:
Or fork here:

The process of creating such a map from an SVG file requires some processing and tweaking over the SVG source:

  • Extracting SVG path strings and creating a JSON object for RaphaelJs

I wrote a simple ruby script to parse the SVG file, extract points and build final paths from them. As my source file had mixed paths, polilynes and polygons, I had to normalize them as paths to simplify later steps. You can find the script here:

I discovered later that there are online services designed to do this job like

  • Tweaking and joining some paths.

There are provinces in Spain composed on more than one territory, for example those composed of islands. In order to unify events detection for province I concatenated all the province's territories on a single path string per province. You can do this because first operation on each string is a "cursor movement", so Raphael will then render exactly the same but with a single Path object.

This is how looks like my paths file after extracting and tweaking, I also added some convenience fields to each path, a number and a name:

  • Loading and rendering paths

Once reached this point things become more straightforward, just need to initialize a Raphael Paper object and iterate over paths drawing and adding some event listeners to them.

  • Optionally you can fit the map in the container div adding the paths to a Raphaël set and then centering RaphaelJs view on its bounding box with Paper.setViewBox(...). (Then I realized this wasn't the best idea, see the update below)

Here is the full loader which renders and centers the map:

Update: Some people noticed serious performance issues with the map on Firefox and IE and after some investigation I discovered the bottleneck were at calculations of the map bounding box. As this data is always the same, I've replaced this calculation for precalculated values obtaining significant improvements in performance.