All right reserved.
mobily.pl - marcin dziewulski © 2009 - 2012

Check out the new website with fresh and new jQuery plugins and tutorials!
Visit jscraft.net

Building an interactive map with Raphael

Posted by: Marcin Dziewulski on 10.02.11

Raphael JS is a powerful library that should simplify your work with vector graphics on the web. Today I will teach you how to create an interactive map from scratch.

At the beginning please create folders and files structure:

Raphael (raphael.js)

Raphael is a small JavaScript library that should simplify your work with vector graphics on the web.

Raphael uses the SVG W3C Recommendation and VML as a base for creating graphics. This means every graphical object you create is also a DOM object, so you can attach JavaScript event handlers or modify them later.

paths.js

It is a file where we are going to keep SVG paths and name of each country.

index.html

As usual, the first step is to lay down the HTML markup.

<!DOCTYPE>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Building an interactive map with Raphael</title>
<link href="css/default.css" rel="stylesheet" type="text/css" />
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/raphael.js" type="text/javascript"></script>
<script src="js/paths.js" type="text/javascript"></script>
<script src="js/init.js" type="text/javascript"></script>
</head>

<body>
	
	<div id="map"></div>
	
</body>
</html>

We are including the stylesheet (default.css) and just before the closing head tag, we are including the jQuery library, Raphael JS library, paths.js and init.js.

Creating paths from SVG file (paths.js)

Scalable Vector Graphics (SVG) is a family of specifications of an XML-based file format for describing two-dimensional vector graphics.

This definition tells that SVG is XML-based file, so you can open it in text editor.

I have found on the web free SVG file with Europe map, so I'm going to use it in this tutorial. Obviously you can use your own vector map. You can export it as SVG file using Adobe Illustrator or Inkspace.

Open paths.js and create new object called paths.

var paths = {}

Then open SVG map and you will see a lot of XML code. Fortunately you need just one value called d. Look on the image below.

Let's create first country path. In SVG file which is using in this tutorial first country is Iceland, so copy d value and create new parameter called iceland in paths object.

var paths = {
	iceland: {
		name: 'Iceland',
		path: // 'd' value
	}
}

You can create another paths in this way.

var paths = {
	iceland: {
		name: 'Iceland',
		path: // 'd' value
	},
	spain: {
		name: 'Spain',
		path: // 'd' value
	},
	portugal: {
		name: 'Portugal',
		path: // 'd' value
	}
	// etc.
}

Creating the map (init.js)

In this part of the tutorial, I'm going to write a script that will show the map on screen.

$(function(){
	
	var r = Raphael('map', 1200, 820),
	// create a canvas object on which to draw our paths
	attributes = {
            fill: '#fff',
            stroke: '#3899E6',
            'stroke-width': 1,
            'stroke-linejoin': 'round'
        },
	// create 'attributes' object with parameters
	arr = new Array();
	
	for (var country in paths) {
		var obj = r.path(paths[country].path); 
		obj.attr(attributes);
	}
	// loop through all paths (paths which are included in paths object), show them and set attributes to them
			
});

Let's create hover event first.

	obj.hover(function(){
		this.animate({
			fill: '#1669AD'
		}, 300);
	}, function(){
		this.animate({
			fill: attributes.fill
		}, 300);
	});

Next I'm going to add click event.

	obj.click(function(){
		document.location.hash = arr[this.id];
		// change document hash (#)
		var point = this.getBBox(0);
		// return the dimensions of an element
		$('#map').next('.point').remove();
		$('#map').after($('<div />').addClass('point'));
		// remove existing 'point' div and create another one
		$('.point')
		.html(paths[arr[this.id]].name)
		.prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
		.prepend($('<img />').attr('src', 'flags/'+arr[this.id]+'.png'))
		.css({
			left: point.x+(point.width/2)-80,
			top: point.y+(point.height/2)-20
		})
		.fadeIn();
		// add html content (name of the country, image and close button), set the position and show element
	});

..and button 'close' click event:

	$('.point').find('.close').live('click', function(){
		var t = $(this),
			parent = t.parent('.point');
		
		parent.fadeOut(function(){
			parent.remove();
		});
		return false;
	});

Finally init.js looks like:

$(function(){
	
	var r = Raphael('map', 1200, 820),
	attributes = {
            fill: '#fff',
            stroke: '#3899E6',
            'stroke-width': 1,
            'stroke-linejoin': 'round'
        },
	arr = new Array();
	
	for (var country in paths) {
		
		var obj = r.path(paths[country].path);
		
		obj.attr(attributes);
		
		arr[obj.id] = country;
		
		obj
		.hover(function(){
			this.animate({
				fill: '#1669AD'
			}, 300);
		}, function(){
			this.animate({
				fill: attributes.fill
			}, 300);
		})
		.click(function(){
			document.location.hash = arr[this.id];
			
			var point = this.getBBox(0);
			
			$('#map').next('.point').remove();
			
			$('#map').after($('<div />').addClass('point'));
			
			$('.point')
			.html(paths[arr[this.id]].name)
			.prepend($('<a />').attr('href', '#').addClass('close').text('Close'))
			.prepend($('<img />').attr('src', 'flags/'+arr[this.id]+'.png'))
			.css({
				left: point.x+(point.width/2)-80,
				top: point.y+(point.height/2)-20
			})
			.fadeIn();
			
		});
		
		$('.point').find('.close').live('click', function(){
			var t = $(this),
				parent = t.parent('.point');
			
			parent.fadeOut(function(){
				parent.remove();
			});
			return false;
		});
		
	}
			
});

default.css

Last step is to add some style with CSS.

#map {
	float:left;
	clear:both;
	width:1200px;
	height:820px;
}

.point {
	position:absolute;
	display:none;
	padding:10px 15px;
	background:#7BB9F0;
	font-size:14px;
	font-weight:bold;
	
	/* CSS3 rounded corners */
	-moz-border-radius:8px;
	-webkit-border-radius:8px;
	border-radius:8px;
}

.point .close {
	display:block;
	position:absolute;
	top:-10px;
	right:-10px;
	width:24px;
	height:24px;
	text-indent:-9999px;
	outline:none;
	background:url(../img/close.png) no-repeat;
}

.point img {
	vertical-align:middle;
	margin-right:10px;
}

Done! Looking nice? Sure, but there is one disadvatage. In our case paths.js has over 400 KB. What do you think about this solution? Leave a comment below.

Comments:

Macxim

02.07.11, 02:13
This is very impressive!!
The map I built is here. http://bit.ly/jcTVMM
I would also like to add the pop-up like you did for each state.
Would it be possible to put links in the pop-up or maybe a description for each state of the map?
Very nice job and awesome resources here.
Keep up the good work!

MyColorsLab

16.05.11, 22:08
Hello George E. Papadakis!

I like the one you made! Could you tell us how you did to insert links to the pop up box. I will really appreciate it!

dodi

01.05.11, 14:20
Greate article thanks for share

Richard

14.04.11, 05:22
Great Tutorial Guys!!

I have a question is there a way to add a link an d description in the pop up window that appears?

Ben

11.03.11, 10:07
Interest of SVG is lossless resizing. But here, there's no resizing : map have a fixed size. Why ?

Rendro

11.03.11, 00:31
Really a nice tutorial. Raphael JS inspired me to create a JavaScript Library for the Html5 canvas element called cajal, because having somethimg like Raphael JS or jQuery really make my life easier ;)

http://github.com/dotsunited/cajal

Andres Hermsilla

11.03.11, 00:11
Great tutorial! One of the best and easiest to understand RapahelJS tuts!

George E. Papadakis

04.03.11, 09:12
Did the same thing, more or less.

Picked up some .ais, assigned IDs to each section, exported them as SVG, loaded them via XHR (and cached them on localStorage) and then painted them using Raphael (mainly).

Here is the result: http://elections.pathfinder.gr/

a. It ain't pretty, but I didn't have time to make something better;)

Damian Ramirez

04.03.11, 07:34
i can see the 'Path' propiety, i just have the polygon. How i can use it? or how i can convert polygon in path?
Damián
Rosario, Argentina

Joy

04.03.11, 05:17
Thank you so much for this plugin!

I have wanted to do something like a map for a long time but didn't think I'd have enough programming skills to do so.

I still need to learn enough javascript to know how to use + build on it, but this is very encouraging!

Write a Comment

If you have trouble reading the code, click on the code itself to generate a new random code.

Options