By Massimo Cassandro

Dynamic Geo Maps with SVG and jQuery

By Massimo Cassandro

When I need to create charts, my first choice is Google Charts or another dedicated library. Sometimes, though, I need some specific features that I can’t find there. In these cases, SVG images prove to be very valuable.

Recently, I had to build a report page that was able to show a map of Italy in which each region had a different color tone according to some values retrieved from a database. Thanks to SVG, this task was very easy.

Creating the SVG Map in Illustrator

First, I drew a map of Italy with Illustrator:

Illustrator Map of Italy

Every region is drawn as a single object, and each of them has its own level, with a name matching the code used in the database to identify its relative data (for example: “tos” for Tuscany).

Finally the map must be saved as an SVG file. You have to pay attention to set the “CSS property” option to “Style Elements” in Illustrator, as shown below:

Illustrator SVG options panel

Opening the file just created, you will see it contains a set of g tags whose IDs match the names of Illustrator levels.

Building our HTML File

Each item contained in g tags has a st0 class so that the stroke and fill CSS properties can be assigned to them:

The file displayed with Brackets

If you try to change those values, the map will change immediately:

Changed map

Now, we can use that code to build our html file with inline SVG as shown below (code has been shortened for convenience):

<!doctype html>
    <meta charset="UTF-8">
    <title>Map Sample</title>
    <style type="text/css" media="all">
        .map svg {
            height: auto;
            width: 350px;
        .map g {
            fill: #ccc;
            stroke: #333;
            stroke-width: 1;
    <div class="map">
        <svg version="1.1" id="Livello_1" xmlns="" xmlns:xlink="" x="0px" y="0px" viewBox="0 -21.6 761 919" style="enable-background:new 0 -21.6 761 919;" xml:space="preserve">
            <g id="sar">
                <polygon class="st0" points="193,463 ...    "/>

            <!-- etc ... -->


You can see that the style attribute inside the svg tag has been erased and replaced by a new one located inside the document head; all g elements have been initially filled with a light grey.

The st0 class is no longer used (you can remove it from your SVG code) and it has been replaced by the .map g selector. Anyway, this is not mandatory, you can use the CSS selectors you prefer.

The second step consists of binding our map to some data retrieved from our database. In this example, our goal is to paint the map according to the population of each region.

Adding the JSON Data and JavaScript

Data is retrieved in JSON format and pasted directly inside our HTML file (in the real world, of course, data would be retrieved using Ajax or similar).

Now our page will contain JSON in our JavaScript file that looks like this (again, abbreviated):

var regions=[
        "region_name": "Lombardia",
        "region_code": "lom",
        "population": 9794525
        "region_name": "Campania",
        "region_code": "cam",
        "population": 5769750

    // etc ...


After that, a color is chosen (in this case, #0b68aa), and we assign it to the region with the highest population value. The other regions will be colored with tones of the main color in proportion to their percentage of the population.

Next we can add some JavaScript.

First of all, we have to determine the region with the maximum population value. This can be done with a few rows of code.

Once a temporary array containing the population values has been built, we can use the Math.max method on it:

var temp_array= function( item ) {
    return item.population;

var highest_value = Math.max.apply( Math, temp_array );

Then we can cycle through all regions’ items and apply to them a percentage of transparency according to the calculation population / maximum value (with a little help from jQuery):

$(function() {
  for(i=0; i < regions.length; i++) {
    $('#'+ regions[i].region_code).css({'fill': 'rgba(11, 104, 170,' 
     + regions[i].population/highest_value 
     + ')'});

This is the result:

Colored map

Adding Interactivity with CSS and jQuery

The map can be improved adding by some interactivity. We want it to show the population value when the mouse is positioned over regions.

First, we add a CSS rule for g:hover and a new info_panel class to style our information boxes:

.map g:hover {
  fill: #fc0 !important;
  cursor: help;

.info_panel {
  background-color: rgba(255,255,255, .7);
  padding: .3em;
  font-size: .8em;
  font-family: Helvetica, Arial, sans-serif;
  position: absolute;

.info_panel::first-line {
   font-weight: bold;   

The !important modifier in .map g:hover is needed to improve the specificity of the fill rule, otherwise it would be bypassed by injected inline CSS.

Then we have to modify our previous for cycle, adding .data() to store information that will be displayed on hover:

for (i = 0; i < regions.length; i++) {
    $('#'+ regions[i].region_code)
    .css({'fill': 'rgba(11, 104, 170,' 
         + regions[i].population/highest_value 
         +')'}).data('region', regions[i]);

Finally, we can complete our script by adding some mouseover effects:

$('.map g').mouseover(function (e) {
  var region_data=$(this).data('region');
  $('<div class="info_panel">' 
    + region_data.region_name 
    + '<br>' 
    + 'Population: ' 
    + region_data.population.toLocaleString("en-UK")
    + '</div>').appendTo('body');
}).mouseleave(function () {
}).mousemove(function(e) {
    var mouseX = e.pageX, // X coordinates of mouse
        mouseY = e.pageY; // Y coordinates of mouse

      top: mouseY-50,
      left: mouseX - ($('.info_panel').width() / 2)

How it works:

  • First, with mouseover, we build a div containing the information to display (region name and population). The div is built every time the mouse hovers over a g element and is appended to the document body;
  • mouseleave removes that div when the cursor is outside the hovered region;
  • The last method, mousemove, retrieves mouse coordinates and assigns them to the generated divs.

Here is the final result on CodePen:

See the Pen KDHfh by SitePoint (@SitePoint) on CodePen.

  • Thanks for the guide! :)

    To get the highest population I would however suggest to use Array’s reduce method:

    var maxPopulation = regions.reduce(function(max, region) {
    return Math.max(region.population, max);
    }, 0);

  • Daniele Pennati

    maybe using d3.js and topojson would be better and simpler, no?

    • Alex Pineda

      For this case probably not, because you have to know d3 and topojson. Here we just need to know basic svg, jquery and css. It’s nice to do things the simple way sometimes. We don’t have to depend on heavier libs all the time and THAT is refreshing.

      • The ease of use is really the reason I wrote this thing. Thank you

        • nmacleod

          Do you have any experience doing this type of SVG map with geolocation data on points or areas?

  • Setudio

    Nice Article, thanks for share :)

  • Dear Massimo, Great Article. I was looking into a way to replace old image html map, that doesn’t allow well the mouseover and transparency. Your solution is clean and simple, but very powerful. So thanks a ton for share it.

  • Cracking article! Thank you – replicated the results using Inkscape and plain Javascript rather than jQuery.

  • Ina Kancheva

    That was super easy and exactly what I needed.
    Thank you! Thank you! Thank you! :)

  • Camilo Saavedra

    Oh my god Man, very very thakns for this helpful

    Chears !

  • Fernando Saavedra

    Amazing tutorial, thanks a lot for this very useful guidelines. I was avoiding learning SVG but after this article (and the results i got from it) I´ll try to dedicate some more time on the subject. Thanks again!

  • Matt

    Hi, great tutorial and I have followed it to build an SVG map (I didnt need the jQuery bit). However I’m having problems with IoS mobile devices needing 2 clicks to activate links from the areas, have you ever had this problem and how did you overcome it? Thank you

  • Oliver

    How to make an external link for the region? Please, answer me.

  • xhiyu

    It helps me a lot.Thank you very much.

  • Igor Potapov

    I have any questions:
    1) How to get data from MySql?
    2) How to create color scale block?

  • Hi
    Can you show me an example of the code that produces that error?

Get the latest in Front-end, once a week, for free.