A jQuery Plugin for Zoomable, Interactive Maps

June 18, 2009

What is it and why was it built?

A couple of months ago we launched a site about Marine Science in North Carolina with one of our design partners, Liaison Design Group. A key part of the project was an interactive map that allowed visitors to find important Marine Science resources in North Carolina.

Each location on the map would be represented by a bullet. Clicking the bullet would bring up more information on the location. Since the locations of the bullets tended to be highly clustered, zooming into select subregions was possible.

We wanted the experience to be engaging as possible but also easily updatable in the future. We settled on jQuery as the interface technology to use as it made it simple to build, display and animate the map. I did a longer writeup on the detailed mechanics of how this worked two weeks ago in one of our most popular posts. Due to the great feedback we got on it, this is a follow-up with a revised version of the code as a jQuery plugin which should make it easier to integrate into other projects.


This project is being used in production on a number of sites. Below is a listing of a couple. If you have used this in a project you would like to see listed, let me know.

NC Marine Science Sici.org Raleigh Photonics
interactive map interactive map interactive map
Liaison Design Shadowbox Creative Liaison Design



This was originally developed for one project with very specific requirements. While I have taken the time to generalize that code into a plugin, I have not made it as generic as I would have liked and will do more in the future to improve it given enough interest. Here is a list of its current biggest limitations:

  • Data Required In Plugin Setup - Ideally all of the required data would be stored in the html pages that drive the bullets. This would allow a CMS to more easily generate additional depth levels without needing to play with the javascript. All that is required in the js now is an array of the sub-regions along with their dimensioning data.
  • Data Accessibility Unaddressed - The plugin currently does nothing on its own to make content available to search engines and those with disabilities. This is left up to the developer to do, though it shouldn't be too challenging since the plugin requires all of the data to be expressed in html.
  • API - Right now it is impossible to programatically interact with the map once it is launched. Eventually it will have a simple API to assist in navigation and other manipulations.

Even with these limitations, this is ready for production and is being used on several sites as seen above in the demos.


There are four main components required to make the plugin run: the background images, links to pages that contain html data in the correct format, some CSS for style and finally the plugin call. Below are instructions on each.

1. Background Images

There are very limited requirements on the background images:

  • They must all be the same size. Sub-region background maps grow to fill the entire map area
  • They should line up. Just prior to zooming, a sub-region map is placed over an area of the main map, if this doesn't line up properly, some of the zooms effect will be lost.
  • The main map should highlight the zoomable regions. The plugin does not otherwise make these obvious. (Though the css could be edited to add a border or background image to the zoomable region.)

2. HTML Data

The plugin assumes a certain structure for the html data it loads via AJAX. As long as the basic structure is kept, a developer is free to add any type of content styled however they would like. Aside from the unavoidable requirements imposed by the animation, all style is isolated to CSS.

The HTML format contains information for the location and applied class of the bullets, a convention based link between the bullets and the pop-up content and the content itself. The html returned should just be a listing of the bullets and popups in the following format:


[POPUP-ID] should be unique for each bullet/popup. The jQuery uses this along with the "-box" convention to open the correct popup when a bullet is clicked.

3. CSS Style

As much as possible, the plugin is designed to operate exclusively on the DOM, leaving styling up to CSS. A basic css file is included with the demo zip. Here is some rough minimal css:

#map { position: relative; width: 700px; height: 470px; overflow: hidden; }
#returnlink { display: block; position: absolute; bottom: 0; right: 0; }
#map a.bullet { display: block; position: absolute; width: 10px; height: 10px; background: yellow; }
#map img.zoomable { }
#map div.popup{ display: none; position: absolute; width: 200px; height: 300px; }
#map div.popup a.close{ display: block; position: absolute; bottom: 0; right: 0; }

The code above will work just fine as a starting point. Obviously a lot of embellishment can be added to make the map look as good as the one's Liaison designed in the examples. Here are some things to note:

  • The main '#map' container must be positioned absolute or relative.
  • Popups must have 'display: none' set to make sure they don't flicker when they are loaded.
  • Popups must be positioned using CSS. The jQuery only shows/hides them.

4. jQuery Plugin Call

The last piece that needs to be put in place is a call to the jQuery zoommap plugin that makes it all happen. In the call, we must pass the in some settings as well as a data structure that sets up the map and its different zoom levels. Here is a call for a simple two level map that contains all of the possible settings:

	// Width and Height of the Map
	width: '500px',
	height: '580px',
	//Misc Settings
	blankImage: 'images/blank.gif',
	zoomDuration: 1000,
	bulletWidthOffset: '10px',
	bulletHeightOffset: '10px',
	//ids and classes
	zoomClass: 'zoomable',
	popupSelector: 'div.popup',
	popupCloseSelector: 'a.close',
	//Return to Parent Map Link
	showReturnLink: true,
	returnId: 'returnlink',
	returnText: 'return to previous map',
	//Initial map to be shown
	map: {
		id: 'campus',
		image: 'images/campus.jpg',
		data: 'popups/campus.html',
		maps: [
			id: 'quads',
			parent: 'campus',
			image: 'images/quads.png',
			data: 'popups/quads.html',
			width: '200px',
			height: '232px',
			top: '18px',
			left: '176px'

Here is a breakdown/description of each of the settings:

  • width/height - The width and height of the map container.
  • blankImage - Path to an (transparent) image that will be used over the zoomable regions until their map is loaded.
  • zoomDuration - Duration in milliseconds of the map zoom effect.
  • bullet(Width/Height)Offset - Offsets that allow the coordinates of the bullets to be placed in the center of the target, rather than the corner.
  • zoomClass - Class that should be applied to the zoomable region imgs.
  • popupSelector - Selector the plugin should use to find the popups in the html
  • showReturnLink - Whether a return link should be shown on child maps
  • returnId - Id to use for the return link.
  • returnText - Text to be placed in the return link.
  • map - The top level map that should be shown.

Additionally each map has the following properties and can infinately nest more maps:

  • id - Id that should be used for the zoomable region.
  • image - Path to the image that should be used for the map. This image should be large enough to fill the entire map space.
  • data - Path to the html data for the maps popups and bullets.
  • width/height - Width and height of the zoomable region.
  • top/left - Absolute position of the zoomable region
  • maps - Children maps.

Here is a minimal call that relies on the default settings:

	width: '500px',
	height: '580px',
	blankImage: 'images/blank.gif',		
	map: {
		// Map structure

And here are the default settings:

settings = $.extend({
	zoomDuration: 1000,
	zoomClass: 'zoomable',
	popupSelector: 'div.popup',
	popupCloseSelector: 'a.close',
	bulletWidthOffset: '10px',
	bulletHeightOffset: '10px',
	showReturnLink: true,
	returnId: 'returnlink',
	returnText: 'Return to Previous Map'
}, settings);

Download the Project Zip

View the project Demo or download the project zip.


This project will be revised in the future and is certainly open to suggestions. If there are any suggestions or questions, please leave them in the comments.


Update (8/2/2011): Daniel Madejak found this plugin and liked it so much that he wrote a Windows desktop application that generates the config files for you! You can check out that application along with the documentation here: http://shaimad.pl/webmapcreator/. Note that it is an early release and improvements are still being made.


Mark's avatar
Dead link to project?
Chris Raymond's avatar
Chris Raymond
Thanks for this script Joel, I adapted it for use on a history site: www.teachinghistory.org/civil-war. The only problem we've been experiencing is similar to some above, in Safari only, the second time you load one of the zoom maps, the popup html file doesn't load. This happens only once the page is ported into a Drupal site, and the error we get is 412 Precondition Failed, which seems to have something to do with how Safari handles http requests inside a Drupal site. Our developer is trying to figure out the problem.
Krupa's avatar
I want to create a map of human chromosome. By clicking onto a position, it will show the disease information. Kindly help me with the code. thanks.
Anuj Jindal's avatar
Anuj Jindal
Popup not working in asp.net

How can we use this jquery properly in asp.net

Image zooming was functioning but popups are not
Eleanor's avatar
Hi, this an awesome tutorial!! and some of the best interactive (non-flash) maps I've seen. I was wondering if there is a wordpress plugin for this or any documentation on how to integrate this into a wordpress page.
rub's avatar
Like your maps, tried the demo but there is a problem, maybe only for me, in IE.
When opening the zoomed map and going back to the main you can not open the zoomed again.
Daniel Madejek's avatar
Daniel Madejek
http://webmapcreator.shaimad.pl/ - Hi, I wrote this small program which makes generating configuration files and poi files much easier.
Early version but it should work.
Daniel's avatar
http://webmapcreator.shaimad.pl/ - something that may help if you don't like to create configuration scripts for this very nice plugin.
It's early version, probably there are many bugs bu works :)
Charlie's avatar
Is there still support for this plugin? I've been playing with it the past couple days, locally it works great in FF, but not Chrome of IE7, the bullets are not showing up. When on I've placed it on a couple webservers, no bullets in any browser. I've tried switching the .html data lists to .php and .aspx, still no luck.
Doug McDaniel's avatar
Doug McDaniel

not sure if you're still watching this thread, but was curious if the example file is up to date. The bullets display in IE8 but the zoomable quad won't zoom. Conversely, in Chrome, the quad zooms, but the initial bullets don't display. Any help appreciated.

Nigel's avatar

I think this is a fantastic script..

I'm planning on using it on a website without the zoom effect and have shown it in test to several people of which two requested that it displays the location on mouseover. i.e. The location name on hovering over the bullets. Is there a simple way to do this? Ideally a hidden layer that displays the place name next to the bullet.

If it's complicated don't worry but it would be a nice addition.


G-Admin's avatar
Hi everybody,

I've detected a hosting server issue, what is the reason for the disabled bullets and popups! My example is working on GoDaddy.com but on 1and1.com I have no bullets and pop-ups! The reason is the server js and css linkink. If somebody has a solution please update me.

Example files are hosted on:

- GoDaddy http://www.novaskinproducts.com/map/example.html

- 1and1 http://miami-midtown.com/map/example.html
Vinod's avatar
Great Work Joel,

I do not think the example satisfies cross browser matrix. The bullet points are not visible in chrome. It would be great if you could give a fix for it.

I am assuming rel is not supported in all browsers.

correct me if I am wrong.

Thank you!

Great Work.
Adam Bell's avatar
Adam Bell
I've been playing around with the plugin and what it can do and it really looks like something I really need for an upcoming project. However, I'm wondering if the only way to zoom in/out of a map is by clicking? My client would prefer to use dropdown menus where you select a continent from a dropdown and then the map zooms in to the continent selected. Is there way to do that using Joel's method?
Adam Bell's avatar
Adam Bell
Great script and so lightweight! I just stumbled upon this and it's almost perfect for an upcoming project I'm working on. One question though. I know you have to set up to allow for the map to enlarge on click or mouse over, but I was wondering if there's a way to control it via a dropdown/pulldown menu? In other words, let's say we have a global map and a pulldown menu of continents. You select North American and then that PNG graphic zooms out on the screen. Select another continent like Europe on the pulldown and a different map zooms in. Is that doable using these scripts? Has anyone tried?
Heath's avatar
I am trying to set up you map plugin to use an multiple image areas as the trigger, is there a quick method to set the trigger?
Andy's avatar
Hey Joel,

fantastic work...really appreciate this!

Currently working on various select fields so people can narrow down the results they see on the zoomed sections, but am having a really tough time getting the value of the select field to update the map data.

I had added something along the lines of what Jasper had done, but with no success:
var social_housing_type = document.getElementById('social_housing_type').value;
social_housing_type.focus() ;

Any thoughts on how I can tie this in?

Thanks again!
Anthony's avatar
I've implemented a separate nav of region names that triggers the corresponding region on the map just as when clicking the a.bullets class. But when I put the nav in a separate div so I can properly position it, the link don't work.

Something like this works
$(this).children('a.bullet, a.navLink').each(function(){

But if you put a.navLink elements inside a div, no dice.

Any thoughts?
Tisna Rudi's avatar
Tisna Rudi
first of all i would like to say thank you for the script. I use it for bandung city interactive map in my website:


I use city map which the file size is about 440 Kb (2176 x 2304px) and background image for pop up with picture or video.

Any suggestion how to add preload image animation while loading? Such as horizontal bar or preload circle animation with text "please wait while loading ...."

I know HTML and CSS, but i don't understand much about javascript and jquery.

Thanks in advance.
Chuck Borowicz's avatar
Chuck Borowicz
I'm a little late to the conversation, but I've been working with the demo files for about a week now and things are looking good in every browser except for Chrome. This seems to be a common question. Is there a solution for getting the bullets to show up in Google's browser?

Thanks in advance!
amori's avatar
Your exemple no function online.
amori's avatar
why there is just zoom of images, whend i get it online ? Offline, there is no problem, all function. Thanks for your answers.
John's avatar
Hello, nice plug you've made here. Does anyone have an idea whether the map can hold 2000 locations?

Douglas's avatar

Fantastic plugin! Thanks so much.

I have the second level zoom working, but cannot, for the life of me, figure out how to get a third level zoom to work.

I understand how to get more than one zoomable region on the initial map (thank you, Ben, for showing where to put the comma between individual map code blocks) but I cannot figure out how to punctuate the code for a third level zoom.

From the original demo code, the following block produces the clickable rectangular region on the initial map:

id: 'quads',
parent: 'campus',
image: 'images/quads.png',
data: 'popups/quads.html',
width: '200px',
height: '232px',
top: '18px',
left: '176px'
/* More maps can be nested
maps : [ ]

The above code creates the clickable rectangular area on the initial map that takes site users to the second level map "quads.png".

I, however, want to create another, third level zoom-in region on the quads.png map, let's say, north-quad.png, but I can't figure out the code. I tried this:

id: 'quads',
parent: 'campus',
image: 'images/quads.png',
data: 'popups/quads.html',
width: '200px',
height: '232px',
top: '18px',
left: '176px'
/* More maps can be nested
maps :
id: 'north-quad',
parent: 'quads',
image: 'images/north-quad.png',
data: 'popups/north-quad.html',
width: '200px',
height: '232px',
top: '18px',
left: '176px'

... as well as a few dozen variations, but I can't get the second level zoom map (quad.png) to have a clickable region that goes to the third level north-quad.png map.

I'd be grateful for any and all suggestions. :)
matt lee's avatar
matt lee
Joel, For a larger map where you wouldn't want to scroll to see the popup, how do you place the popup a certain distance from the bullet?

Thanks for your help


Leave a comment