Building an interactive map and world clock using HTML 5 & jQuery

Posted in Web Design on Tuesday, 27th September 2011 at 12:40PM

Building an interactive map and world clock using HTML 5 & jQuery

I have recently been working on a serviced office space rental site called NewOfficeAsia.com which included the need for an interactive map highlighting the countries which the company dealt with.  There was also the requirement that the map display the current local time for the capital of the active country or area. 

For several years my first port of call for a project such as this would have been Flash, but this is no longer the case thanks to tools such as the jQuery javascript library and its wealth of community built plugins which makes coding these sorts of things relatively straight forward whilst negating the need for browser plugins.  Creating the graphics for each country and positioning them correctly was fiddly and time consuming but the actual coding was fairly simple.

View live demo

There are quite a few different elements working together here to create the desired effect so I will break down each aspect individually before describing how they were brought together.  I started with a div container to hold the map which I named #iMap and to which I applied the following styles.

#iMap {width: 626px;  height: 352px; position: relative; }

1. Crosshairs

The first elements I added to #iMap were two line graphics to which I gave the classes 'latitude' and 'longitude' and applied the following style to position them within the map holder.

.latitude {position: absolute; left: 300px;}
.longitude {position: absolute; left: 0px; top:127px;}

These were to become my crosshairs which needed to move with the mouse.  This was achieved with a simple piece of jQuery.

/* bind the mousemove event to the map container */
$('#iMap').bind({
    mousemove: function (longLat) { 
/* whenever the mouse moves get its position */
        var x = longLat.pageX - this.offsetLeft;
        var y = longLat.pageY - this.offsetTop; 
/* check that the mouse is within the confines of the map  */
        if ((x >= 10 && x <= 616) && (y >= 10 && y <= 342)) { 
/* and set the position of the lines accordingly */
            $('.latitude').css('left', (x - 15));
            $('.longitude').css('top', (y - 15));
        }
    }
});

2. The map graphic

Map of Asia showing dots only

I created the map graphic from scratch to fit the exact space I had available and added it to the container with a 'usemap' attribute which allowed me to create an image map for the countries (step 4).

<img src="/img/global_map.png" alt="Countries we cover" width="592" height="312"  usemap="#globeImageMap" id="globalMap"/>

3: The country rollover images

I wanted each country to glow yellow on rollover so I had to create a separate image for each country and add all of these to the container with a relevant class name.

Cut-out of China

There were over 40 in all but here is an example of a few.

<div id="countryImages">
<img src="/img/countries/bahrain.png" alt="Bahrain" class="bahrain" width="17" height="16">
<img src="/img/countries/china.png" alt="China" class="china" width="260" height="184">
<img src="/img/countries/hongkong.png" alt="Hong Kong" class="hongkong" width="20" height="18">
<img src="/img/countries/india.png" alt="india" class="india" width="128" height="135">
</div>

These images then needed to be positioned within the container to fit exactly over their corresponding location on the map.  All were set to 'display:none' except the UK as I wanted it to appear selected on initial page load.

#countryImages .bahrain  {left: 105px; top: 139px;}
#countryImages .china {left: 205px; top: 8px;}
#countryImages .hongkong {left: 362px; top: 157px;}
#countryImages .india  {left: 182px; top: 100px;}

4. The image map and hot-spots

Editing the NewOfficeAsia.com hotspots

In order to link the map graphic with the countries and make them highlight on hover I needed to create an image map which would tell the browser which areas of the container corresponded to which country images.  Whilst my favourite code editor is Coda by a long shot, this is where Dreamweaver really comes in to its own.  I opened up the page in Dreamweaver and clicked the map graphic to select it.  Using the polygon image map tool, I drew around each country to plot its co-ordinates into an image map.  I then went through and added a relevant id to each area of the image map in order to distinguish them from each other.  If you don't have Dreamweaver there are online services that perform a similar task such as this one http://www.image-maps.com/.

The resulting code was an image map containing an area for each country defined by a set of co-ordinates.  Here are a few examples.

<map name="globeImageMap" id="globeImageMap">
<area shape="poly" id="bahrain" coords="112,152,115,153,116,150,118,147,116,143,113,143,109,146" href="/serviced-offices/manama?group=bahrain"/>
<area shape="poly" id="jordan" coords="51,133,52,127,53,124,57,124,59,122,65,123,59,124,63,128,61,131,58,132,55,135" href="/serviced-offices/amman?group=jordan"/>
<area shape="poly" id="qatar" coords="116,155,115,152,117,150,120,150,121,154,119,158" href="/serviced-offices/doha?group=qatar"/>
</map>

Each of these areas could have an 'href' attribute applied to it if needs be and link to an external page but in this case I just needed them for the interactive map so their unique id was enough.

5. The world clock

The next step was to generate the world clock for each time zone that would be represented on the map.  For this I used a jQuery plugin called jClock which provides multiple javascript clocks which can have their UTC values adjusted for each timezone.  I added a paragraph to the map container for every country to display the name of its capital city and left a space for its local time.

<div id="utcAll">
<p class="china"><span>BEIJING:</span> <span class="UTC20 clock">00:33:24</span></p>
<p class="hongkong"><span>HONG KONG:</span> <span class="UTC20 clock">00:33:24</span></p>
<p class="india"><span>NEW DELHI:</span> <span class="UTC17 clock">21:33:24</span></p> 
<p class="indonesia"><span>JAKARTA:</span> <span class="UTC19 clock">23:33:24</span></p>
</div>

These were then styled to position them and hide all but the initial country (UK).

#utcAll p {display: none; position: absolute; top: 0; right: 0px;} 
#utcAll p.uk {display: block;} 

The jClock function was then called on the relevant paragraphs to add the correct local time

var optionsUTC14 = {
        utc: true,
        utc_offset: +2
      }
  $('.UTC14').jclock(optionsUTC14);

6.  Country names

The final content area I needed was a paragraph for each country to display its name.

<div id="allCountries"> 
<p style="height: 25px; overflow: hidden;" class="china country"><span>Click to view serviced offices in </span>China</p>
<p style="height: 25px; overflow: hidden;" class="hongkong country"><span>Click to view serviced offices in </span>hongkong</p>
<p style="height: 25px; overflow: hidden;" class="india country"><span>Click to view serviced offices in </span>india</p>
<p style="height: 25px; overflow: hidden;" class="indonesia country"><span>Click to view serviced offices in </span>indonesia</p>
</div>

Which also needed to be styled into place and hidden (except for the Thailand which will be visible on load).

#allCountries p{position: absolute; left: 20px; top: 15px; display:none; z-index: 10;}
#allCountries .thailand {display: block; z-index: 100;}

7: Pulling it together with jQuery

So, all the content is now present, the map graphic, an image for each country, the moving cross hairs, the capital cities with local times and the country names.  All that's needed now is to make sure the right content shows when the user hovers over each country's image map area.

/*attach a mouseover funtion to all the image map areas*/
$("#globeImageMap area").mouseover(function () { 
/* get the id of the active image map area and pass it to a variable*/
    var targetCountry = $(this).attr('id'); 
/* hide all world clock paragraphs except for the target country */
    $("#utcAll p").hide();
    $("#utcAll p." + targetCountry).show(); 
/* hide all country title paragraphs except for the target country */
    $("#allCountries p").hide();
    $("#allCountries p." + targetCountry).show(); 
/* make sure the Thailand which is already visible on load gets hidden when the first country is rolled over*/
    if (targetCountry != 'thailand') {
        $('img.thailand').hide();
    } 
/* show th target countries rollover image */
    $('img.' + targetCountry).show();
}); 
/* when the mouse leaves the image map area, hide the corresponding country's image  */
$("#globeImageMap area").mouseout(function () {
    var targetCountry = $(this).attr('id');
    $('img.' + targetCountry).hide();
});

And that's it!  Hopefully now the correct country image and details should show when you hover over it on the map.  I found that some of the smaller countries such as Singapore and Hong Kong needed their image map hot spots increased a little in order to make them useable but apart from that it worked pretty much flawlessly.

Update: It's been raised in the comments that if you place the country images with a higher z-index than the image map, they may obscure the hotspots and cause the map to flicker.  This was not an issue in my example as the mapped image was largely transparent so could be placed above the countries without issue.  A solution is posted below.

View live demo

Add your comment

Remember me?

Notify me of follow-up comments?

You do exceptional work Michael, and write very thorough tutorials.  I am trying to decide whether to use JQuery or Flash for an interactive map on an upcoming project, and I think you have influenced my decision.

Thank you for sharing this bit of treasure you have made.

Posted by William Muncrief on Saturday, 1st October 2011 at 1:54AM

Wow, very impressive.  It’s great to see how a mixture of jQuery, CSS, and images can create what many would assume is a Flash interaction.  Way to think outside of the box and come up with such an elegant solution.  Thanks also for sharing how you did it.

Posted by Ryan Battles on Tuesday, 4th October 2011 at 1:41AM

Hi,

Thanks for this great example. I’m having trouble getting the hover images to appear without glitching however.

They don’t seem to stay selected when hovered. Is there any reason for this? I’m using it for a client and have gone over everything I can think of to fix.

Please help smile

Thanks,

Posted by ash white on Tuesday, 13th December 2011 at 2:50PM

Hi Ash.  One thing that springs to mind is that the rollover images are appearing, obscuring the image map which in turn disables the hover state and causes them to vanish again before starting the cycle all over again.

I should have pointed out in my example that the mapped image has actually got a z-index higher than the individual country images but that you still see the country images when they appear because the mapped image is mainly transparent (except the dots).  If you are using a non-transparent mapped image then you would need the countries to have a higher z-index which would cause the problems you described.

If this is what’s happening then my suggestion would be to map your image as normal and then to duplicate it.  Set the z-index of the original mapped image to be higher than the individual countries so that the hotspots are never obscured by them.  You would then need to make the original mapped image 100% transparent so that you can see your individual countries through it as they appear.  This should solve the issue of the flickering if my theory is correct but you would then not be able to see the mapped image so insert the duplicate (non transparent) version in the same position but at a lower z-index than the individual countries so that they become sandwiched in between the transparent image map and the non-transparent duplicate.

Let me know if this works.

Posted by Mike on Tuesday, 13th December 2011 at 8:30PM

Hi Mike,

I did this just before your reply which worked thanks. I’ve set the main map image as a background image to the #iMap. Then used an overlay image to take care of the mapping whilst the z-index allows the hover states to appear fine.

I’m trying to figure out how to get a tooltip to pop up when hovered over too. Have you experimented with anything like that for this demo? I’ve looked at some quick solutions on the web but they all require me to use a class on the element (hover image) for the pop up to appear.

Unfortunately they already have a class but if you have any tips I’d be very grateful.

Thanks for your speedy reply smile

Posted by ash white on Tuesday, 13th December 2011 at 8:52PM

Hi Ash.  I’m afraid I’ve not tried this but I don’t see why you shouldn’t be able to just add a set of positioned tool-tips which are triggered at the same time as the countries.  Place them in a container separately to the countries and just repeat the hover code for the countries for each tool-tip so both show.

Posted by Mike on Wednesday, 14th December 2011 at 8:56AM

Just what i needed for a project of mine. Very well posted.

Thanks

Reworx Design

Posted by Darren on Tuesday, 24th January 2012 at 5:16PM

This is almost what I wanted but what I would like to know how you would be able to click on a country and the image (for the image map) would change to a new image and the country you clicked on would be highlighted. Any ideas?

Posted by Michelle on Thursday, 17th May 2012 at 7:56PM

Hi Michelle.  That should be fairly straight forward to achieve by changing the onmouseover event to a click event and removing the mouseout event.  I’ll see if I can put together a quick demo for you if you want, and send it over.

Posted by Mike on Friday, 18th May 2012 at 9:02AM

Nice and good tutorial! Worked very well for me. But now I’m trying to connect different countries with an anchor link to a piece of text on the same page. I added this: href=”#uk” to the area shape. And added this to the title of the text about the uk: <a name=“uk”><h1>The United Kingdom</h1></a>.

But it’s not working. I also tried it without <H1> tags. The page goes down only a tiny bit. Any suggestions would be nice. Thanks.

Posted by Paul on Friday, 10th August 2012 at 11:59AM

Hi Paul.  Have you tried using id instead of name like this:  ‘<a id=“uk”><h1>The United Kingdom</h1></a>’

Posted by Mike on Monday, 13th August 2012 at 8:47PM

This is an excellent tutorial, but seems that my jQuery is not detecting the mouse over event in the regions of the specified countries. if I take off the vertical and horizontal lines that follow the pointer it work perfectly, but when I add the lines it does not detect the mouseover event. Any ideas? I’m assuming that the images of the lines are interfering with the detection of the mouseover event.

Posted by artud2000 on Tuesday, 21st August 2012 at 2:45PM

got the solution I added pointer-events: none; to the css of the latitude and longitude lines.

Posted by artud2000 on Tuesday, 21st August 2012 at 3:37PM

Great, glad you got it sorted and thanks for posting back.

Posted by Mike on Tuesday, 21st August 2012 at 3:41PM

About the vanishing and showing again effect a simpler solution is to add this javascript code

$(’#countryImages img’).mouseover(function () {
  var targetCountry = $(this).attr(‘class’);
  $(’#countryImages img.’ + targetCountry).show();
  });


$(’#countryImages img’).mouseout(function () {
  var targetCountry = $(this).attr(‘class’);
  $(’#countryImages img.’ + targetCountry).hide();
  });

This way even if the country image appears above the image of the map, functions the same way as the corresponding area.

Posted by Lemonia on Wednesday, 17th October 2012 at 2:46PM

Awesome job Michael! Really detailed and informative! smile

Posted by Ahmad on Thursday, 6th December 2012 at 8:00AM

Michael's Paintings

San Francisco

San Francisco
32 x 52 cm
Acrylics and Indian ink on canvas

Michael's photos

Beijing Birds Nest Stadium

Beijing Birds Nest Stadium

Featured Web Project

Infinity production page

Project: Infinity Productions
URL: http://www.infinityproductions.co.u