Introduction to SVG scripting: an interactive map

This is a brief introduction to how you can create make an SVG interactive using ECMAScript. For an introduction to how to general SVGs please take a look at my SVG tutorial. As an example, I'll create an interactive map, which seems to be a popular use for SVGs. I've written an overview of alternative methods for adding interactivity to an SVG here. There are basically only four functions you need to know:

  • getElementById("X") - gets the element with an id of X
  • element.getAttributeNS(null, "X") - gets the value of attribute X
  • element.setAttributeNS(null, "X", "y") - sets the value of attribute X to y
  • - refers to the text in a text element

Once you know how to use these (and how to trigger events), you can create all sorts of impressive effects with minimal effort.

Step 1. Get some country-based data

The first step is to get some data. Presumably, if you want to create a map, it's because you have some data you display. If you're looking for sources of digital data, you could try the world bank, the Guardian Datastore, (for UK-based data) or (for US-based data). For this tutorial, I'm going to use some data from the WHO, but it's actually quite tricky to extract data from their website.

Step 2. Get a map

Now you need an SVG map. You can either draw your own in a program like Inkscape or Adobe Illustrator (or you could theoretically write the SVG from scratch), or you can download an open source SVG map from Wikimedia. If you do get a map from Wikimedia or some other source, you'll may have to clean it up (moving elements out of groups) to get all the interactions to work correctly. A key feature your map needs is for the country elements (almost certainly paths) to have an id attribute that gives their name.

For this tutorial I'm using a map of Africa that I got from Wikimedia and spent way too long cleaning up. I've also add a CSS hover effect (described here). You can download the map at the bottom of this page under Attachments.

Step 3. Initialise the SVG

In my simple ECMAScript example, I only changed the attributes of elements passed by However, to have more control over the SVG DOM, we need to be able to refer to our SVG. We can do that by creating the following function.

<script type="text/ecmascript">
  function init(evt) {
    if ( window.svgDocument == null ) {
      svgDoc =;

We can now use the svgDocument object. Note that all of our code must be written in the <script> element and CDATA[ ] label.

Now we need to call our function, which we do with the onload event in the <svg> element: the svg tag should look something like this:

<svg width="400" height="400" version="1.1"
xmlns="" onload="init(evt)" >

Step 4. Display country names

The first script effect I'll demonstrate is how to change the text in a <text>. This can be used to achieve a variety of effects, such as displaying the name of an object when the mouse is held over it (see my tooltip tutorial). For this tutorial, we'll just display the country name at the bottom of the image. In my previous interactive SVG map I achieved this effect using the set command, but that's quite inefficient as it requires a separate text element for every country. Using ECMAScript is a more efficient method.

First, we add an empty text element to the bottom of the image:

 <text class="label" id="country_name" x="10" y="390"> </text>

I've given it a class, so it's easy to style, and an id, so I can target it within a function. I've also made the <text> element contain a single space; if you don't have anything here, then the text's value will be null, which will cause problems in the next step.

The next step is to create a function (within the <script> tags) that changes the text value:

function displayName(name) {
  svgDoc.getElementById('country_name') = name;

This function selects the element with the id 'country_name', and sets its, i.e. the value between the tags, to equal to a passed name. To call the function when a country is moused over, you need to add an onmouseover event to each path or group tag making up a country. The event should call the function and pass the relevant name:

onmouseover="displayName('Whatever country name')"

It's a bit of a pain to manually add this code to lots of countries so using Python to edit the XML is a good idea if you know how to. The map should now look something like this:

5. Colour a country

Assuming each path or group of paths representing a country has a sensible name (and this is where it pays to have a good starting map), it's easy to colour a country. For example, we can colour Libya green:

country_id = 'libya'
colour = '#004400'
country = svgDoc.getElementById(country_id);
country.setAttributeNS(null, 'style', 'fill:'+ colour);

However, if you're making a chloropleth map, you are likely to group countries into a few different classes and associate each class with a colour. For this, it makes sense to use classes and CSS. This will also make it much easier to change colour scheme later if we so wish.

So first we define a few colours within the style element:

.colour0 {fill: #b9b9b9;}
.colour1 {fill: #ffa4a9;}
.colour2 {fill: #cc6674;}
.colour3 {fill: #993341;}
.colour4 {fill: #66000e;}

Then we can define a function that finds the class of a given country and adds an additional class of "colourX", where X is a given number.

function colourCountry(name, colour) {
   var country = svgDocument.getElementById(name);
   var oldClass = country.getAttributeNS(null, 'class');
   var newClass = oldClass + ' colour' + colour;
   country.setAttributeNS(null, 'class', newClass);

For example, we could colour a Algeria with our third colour like so:

colourCountry('algeria', 2)

6. Colour multiple countries

We can use the function we just defined to colour many countries at once with a loop. The following function colours an array of countries with a given class number: 

function colourCountries(data, colour){
    for (var country=0; country<data.length; country++){
        colourCountry(data[country], colour);

We use this function like so:

var data1 = ['ghana', 'togo']
var data2 = ['burkina-faso', 'cameroon', 'chad'];
colourCountries(data1, 1);
colourCountries(data2, 2);

It should be pretty clear that we can generalise this approach with another loop, although it does require creating an array of arrays. Although this is perhaps not the intuitve data struture, it is easy to program. We can arrange our data in an array, such that each value in the array is an array of countries that share a colour. For example:

var data1 = [['ghana', 'togo'],
             ['burkina-faso', 'cameroon', 'chad'],
             ['congo', 'cote-ivoire']];

In this example, Ghana and Togo are given colour 1, Burkina Faso, Cameroon and Chad are given colour 2 and Congo and Cote d'Ivoire are given colour 3. We can transverse this array of arrays and add the colours with an updated colourCountries() function:

function colourCountries(data) {
  for (var colour=0; colour<data.length; colour++){    
    for (var country=0; country<data[colour].length; country++){
      colourCountry(data[colour][country], colour+1);

Blank Africa Map.svg166.46 KB
Blank map display names.svg168.39 KB
colour_with_class.svg167.05 KB