All right reserved.
mobily.pl - marcin dziewulski © 2009 - 2012
Visit jscraft.net
Building an interactive map with Raphael
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:13MyColorsLab
16.05.11, 22:08dodi
01.05.11, 14:20Richard
14.04.11, 05:22Ben
11.03.11, 10:07Rendro
11.03.11, 00:31Andres Hermsilla
11.03.11, 00:11George E. Papadakis
04.03.11, 09:12Damian Ramirez
04.03.11, 07:34Joy
04.03.11, 05:17Write a Comment