How To Create an Interactive Map with jQuery

In this tutorial, I’m going to show you how to create a jQuery interactive map. We’ll start all the way from the HTML markup, to CSS, and lastly the JavaScript. For those of you that have an addiction to caffeine (like me) I have also included the CoffeeScript version of our JavaScript file. Awesome, huh? Not only that, but I’ve also included all the source code at the end of the tutorial.

Before we start, you can take a sneak peek at the final demo.

jQuery-Interactive-Map

Check out an interactive demo of the final result.
View Demo

The HTML Markup

Now lets get going. We’ll start with our HTML markup. I’ll explain every step.

<div id="wrapper">
	<div id="map_container">
		<a class="marker" style="top:44%; left:67%;" data-info="iran"></a>
		<div class="info_box"></div>
		<div class="info" id="iran">
			<h2>Iran Republic - Asia</h2>
			Lorem ipsum dolor sit amet, mel offendit facilisis cu, per ei detraxit electram temporibus, eu ad
		</div>
	</div>
</div>

We begin our markup by creating a div with the id wrapper that will be positioned at the center of our page, then inside it we have our map_container div. This will contain everything, including the map itself. We will set the whole map as a background image of this div then we’ll position the div using the css relative positioning (I’ll explain this when we look at our CSS code).

The next element is the anchor tag with a marker class and some inline CSS position style. Something to note here is the custom data attribute data-info="iran". It’s an HTML5 attribute that we’ll use to uniquely identify each country.

Next is the div with the class info_box. This will be populated with information about different countries when we move a mouse over each marked country. And lastly we have another div element with class="info" and id="iran". See how that id matches the value of our data attribute on the anchor tag? That’s very important because we will use those attributes to link the anchor tag to its respective information.

That’s the end of our HTML markup. Just note that in the final code I have gone ahead and added more anchor tags and more divs with class “info”, for the rest of the countries.

The CSS

Now lets check out our CSS code.

#wrapper {
	margin: 80px auto;
}

The above code is self explanatory. Don’t forget that if you have any problems understanding anything, you can leave a comment below and I’ll gladly explain.

#map_container{
	background: url(../_images/world_map.png) 0px 0px no-repeat;
	height: 415px;
	width: 840px;
	position: relative;
	color: #fff;
	margin: 0px 0px 0px 0px;
}

The next code is for the map_container id. Note that we set its position to relative because we will be positioning our countries “absolutely” inside this container.

Allow me to give an analogy.

Tanzania is in Africa. If you want Tanzania to still be in Africa after the Earth has rotated on its axis, then the Earth’s CSS position has to be set to relative and Tanzania’s position has to be set to absolute. Otherwise, some Tanzanians may find themselves in Europe when they wake up! (I know, some may actually like that, but the worst case scenario is that the whole of Tanzania may become a low budget version of Atlantis, sinking in the middle of the Indian ocean! Don’t be scared though, that [probably] ain’t gonna happen)

Next up we have our anchor tag with the class marker. For this we use a CSS sprite to position the background images. The CSS position of our anchors is absolute.

Now, each of our anchor tags will have three different states: the first is the default state (where a point on the map is marked). At this state, the background image will show red, thus the background image position is 0%(x-axis) and 0%(y-axis). Next up we need the background image to be different (orange) when you hover over the marked area, so our anchor’s background image position will move up by 50%(in the y-axis) while it stays at 0%(x-axis). Lastly we have the current state, which is when the marked area is the current selected location. This will show green, so we move the background image to 100%(y-axis).

a.marker{
	position: absolute;
	background: url('../_images/markers.png') 0% 0% no-repeat;
	height: 32px;
	width: 20px;
	display: block;
	cursor: pointer;
}

a.marker:hover{
	background: url('../_images/markers.png') 0% 50% no-repeat;
}

a.current{
	background: url('../_images/markers.png') 0 100% no-repeat;
}

Our last piece of CSS code should be familiar now because most of these css properties have been explained within our tutorial. Something to note here is that we set our info_box‘s display property to none and the info class as well. We will change the info_box‘s display property using jQuery when the mouse moves over a marked area on our map.

.info_box {
	display: none;
	position: absolute;
	width: 240px;
	height: 115px;
	overflow: hidden;
	padding: 5px 10px;
    background-color: rgba(31,32,62,1.0);
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    border: 1px solid #fff;
}

.info_box h2{
	border-bottom: 1px solid #515a6b;
	color: #515a6b;
}

.info{
	display: none;
}

The jQuery Code

Now that we are done with the CSS & HTML, lets look at our jQuery code. I will paste all the code without the comments and explain each line.

Before I do that though, lets first see what we need to happen. We need to be able to put a mouse over a marked location on the map, and when we do, a box should fade in above that particular location showing more information about it. Then, when we move the mouse away we need the information to disappear by fading out.

Knowing that, we want to control what happens when a user puts a mouse over a location on the map and when the mouse moves away from the map, so we add jQuery’s mouseover() and mouseleave() event listeners on our locations. See the code below.

$(document).ready(function(){
	$('a.marker').mouseover(function(){
		var $link = $(this);
		var contryName = $link.data('info'); 
		var linkPosition = $link.position();
		var infoBoxTopPos = linkPosition.top - 130 + "px";
		var infoBoxLeftPos = linkPosition.left - 120+ "px";
		var container = $('.info' + '#' + info).html();
		$('a.marker').removeClass('current');
		$link.addClass('current');
		$('.info_box').html(container).css({
			'top' : infoBoxTopPos,
			'left' : infoBoxLeftPos
		}).fadeIn(1000);
	}).mouseleave(function(){
		$('.info_box').fadeOut(100);
	});
});

var $link = $(this)

It is not good practice to make jQuery dive into the DOM every time we need to know the value of the keyword this, so we cache it by assigning it to a variable. You may have noticed that our variable is prefixed with the $ symbol because doing that will give our variable all the jQuery magic, so now we can call jQuery functions on the $link variable.

var countryName = $link.data('info')

This line will return the value of our custom data attribute. Remember in our html, we have set a custom data attribute to all our anchors, so for example if you have <a class=”mark” data-info=”iran”></a> the value “iran” without the quotes will be returned and assigned to a variable countryName

var linkPosition = $link.position()

This line will assign the top and left position of an element to a variable called linkPosition based on its parent container. If you want the returned value to be based on the document object then use the offset() function (read more about this here). Now using the variable (linkPosition), we can get the top position by linkPosition.top(), and the left position by linkPosition.left().

You may have noticed that we need these positions (top and left) to be in pixels and to display on top of a marked position that we have put our mouse over. That’s why we subtracted 130 from the top position and 120 from the left position and we have concatenated with “px” at the end, so that the value returned will be similar to 234.23px instead of 234.23.

Now when we put our mouse over a marked area on our map, we don’t need any other marked area to have a ‘current’ class assigned to it, so we clear that with this piece of code:

$('a.marker').removeClass('current'),

then we add the class ‘current’ to the area that we have our mouse over with this code:

$link.addClass('current').

Just remember that the variable $link refers to the area our mouse is focusing on right now.

Next up, var countryName = $link.data('info')

This code will return whatever value is assigned to an anchor’s data-info attribute (refer to the part where we discussed the HTML markup). Each of our anchors has a custom data attribute called data-info, so if the anchor looks like this <a href=”#” data-info=”iran”></a> then the above code will return “iran” without the quotes. However, you can also achieve the same result by using var countryName = $link.attr('data-info'), but I prefer to use the data method more. (You can read more here)

The next thing is to get the information related to the current point on the map that we have our mouse over. We already know that each anchor has a data-info custom attribute. Now looking back on the HTML section you will notice that there’s this div <div class=”info” id=”iran”></div>. Note that the value of the “data-info” attribute on the anchor is similar to the “id” of the div with a class “info”, which is how we intend to link between these two. Now when a user puts a mouse over point on the map, we know that there is a div with class “info” that has the same id as the value of our “data-info” attribute of the anchor point that our mouse is focusing on at current instance.

Now what we need is to get all the html of that div and assign it to a variable so that we can easily access it and that’s what this piece of code does:

var container = $('.info' + '#' + countryName).html()

(Remember this is like telling jQuery, get me all the html contained within an element, in our case a div that has class set to “info” and the id which is equal to this point’s data-info attribute’s value and assign that to a variable called container)

Next up we append all this html (which we have stored in the container variable) to the div with class info_box (which is hidden with css), then position that div by changing its css top and left position and then show it by fading it in and we accomplish that with this piece of code:

$('.info_box').html(container).css({
	'top' : infoBoxTopPos,
	'left' : infoBoxLeftPos
}).fadeIn(1000);

Lastly we add the mouseleave event listener to our anchor so that when you move your mouse’s focus from the anchor point on the map, the information on top of that anchor disappears by fading out.

.mouseleave(function(){
	$('.info_box').fadeOut(100);
});

Bonus Code (CoffeeScript)

Now as promised, I will also show the CoffeeScript code that can accomplish the same result but with cleaner and more readable code.

jQuery ->
	$('a.marker')
	.mouseover ->
		$link = $(this)
		countryName = $link.data('info')
		linkPosition = $link.position()
		infoBoxTopPos = linkPosition.top - 130 + "px"
		infoBoxLeftPos = linkPosition.left - 120+ "px"
		$('a.marker').removeClass('current')
		$link.addClass('current')
		container = $('.info' + '#' + info).html()
		$('.info_box').html(container).css({
			'top' : infoBoxTopPos,
			'left' : infoBoxLeftPos
		}).fadeIn(1000)
	.mouseleave ->
		$('.info_box').fadeOut(100)

Points To Note About CoffeeScript

The function() keyword is replaced with -> (most people call it dash-rocket). The var keyword for assigning variables is not needed, those curly braces that dominate most programming languages are replaced with indentation and the semi-colons at the end of each function are not needed. As a result you will find yourself writing this code in less time than if you were to write it all in normal JavaScript, especially when there’s lots of JavaScript code to be written.

Moving Forward

This tutorial may not fit your current project, but I’m sure the knowledge gained is worthwhile. Remember that the most important thing is practice. I’ve dropped all the demo code below for you to download and play with.

Download the code here!

About the Author

Zachariah Ngonyani is a web developer / designer based in Arusha,Tanzania. He works with a small design firm in Arusha called DSTL. He loves learning, teaching and creating good websites / web apps.

  • Mike

    Great article… Looking forward to more soon…:-)

  • emineys

    nice tutorial, soo helpful.

  • David Gray

    Cheers Zachariah for sharing the knowledge….looking forward to more as well…..!!

  • Good stuff, Zech!

  • Thanks @martianskills:disqus, props for the edits as well, nice touch

  • Emmanuel

    Great. Working through the tutorial.
    PS: The link for downloading the code isn’t working!

    • what happens when you click on the link?

      • Emmanuel

        It was downloading a file without an extension. It is working well now, thanks!

        • great to hear that its working

  • Murad Swaleh

    Great tut Zech.

    • Thanks mate @muradswaleh:disqus

  • Olaw2jr

    Nyc Article Learned somthing

signed. martians.™