The Basics
To get started, we need to load up jQuery and the Google Maps API library. Note that when including Google Maps you have to set thesensor
parameter to true if you are detecting the user’s location (say via GPS). For the typical browser scenario though false is fine.
<!DOCTYPE html>
<html>
<head>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js">
</script>
<script
type="text/javascript"
src="http://maps.google.com/maps/api/js?sensor=false">
</script>
<script>
// New code goes here
</script>
</head>
<body>
<div id='map_canvas' style='height:500px; width: 700px'></div>
</body>
</html>
That doesn’t show a map yet, it just gets everything ready with the right libraries loaded and a div
to place the map into. The rest of the article will assume this basic template.
Every page with a map on it will need to start by actually creating a map object. This is done by specifying some basic options, such as the initial location and zoom level, and the container to place the map into.
$(function() { // jQuery onload handler
var melbourne = new google.maps.LatLng(-37.813611, 144.963056);
var mapOptions = {
zoom: 12,
center: melbourne,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map($("#map_canvas")[0], mapOptions);
});
From here, we can place various items on to the map. The most common is the “Placemark”, which you have no doubt seen on countless maps, but there are other options such as circles and images. Let’s put a marker on top of Flinders St Station, the hub of Melbourne’s train network.
// continuing on from above
var map = new google.maps.Map($("#map_canvas")[0], mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(-37.818078, 144.966811),
map: map,
title: 'Flinders St Station'
});
There are plenty of options for making your markers a little more snazzy. Let’s give this one a nicer icon and some gratuitous animation.
var marker = new google.maps.Marker({
position: new google.maps.LatLng(-37.818078, 144.966811),
map: map,
title: 'Flinders St Station',
icon: 'http://google-maps-icons.googlecode.com/files/train.png'
});
marker.setAnimation(google.maps.Animation.BOUNCE); // Also try DROP
That bounce is quite annoying. Please do remove it again before continuing. I believe I have made my point: you can customize your placemarks.
Behaviour
The Google Maps API exposes a large number of events that we can react to in our program. They are documented against each type of object you can place on a map. For this example we will stick to the plain vanilla click event, but there is plenty of scope for interesting interactions with other mouse events and drag/drop.google.maps.event.addListener(marker, 'click', function() {
alert("clicked Flinders St");
});
This is the hook we need to create interesting interactions that go above and beyond the standard “info window” pop-up that is the standard dialog used on Google Maps. Using the manipulation and animation functions provided with jQuery, it is trivial to put together something shiny. We will use a semi-transparent overlay that slides into the map to provide extra detail about the clicked placemark. This requires some new HTML:
<div class='map'>
<div id='map_canvas' style='height:500px; width: 700px'></div>
<div id='placeDetails'>
<h1>Flinders St Station</h1>
<p>
This is a pretty major train station.
</p>
</div>
</div>
It also requires some styling for the new “info window”. There are quite a few lines of CSS in the following snippet, but don’t panic it should be pretty simple to follow. The important parts are labeled with comments.
<style>
.map {
width: 700px;
/* The following are required to allow absolute positioning of the
* info window at the bottom right of the map, and for it to be hidden
* when it is "off map"
*/
position: relative;
overflow: hidden;
}
#placeDetails {
/* Place the div off the bottom right of the map */
position: absolute;
width: 300px;
bottom: 0;
right: -320px;
padding-left: 10px;
padding-right: 10px;
/* Semi-transparent background */
background-color: rgba(0,0,0,0.8);
color: white;
font-size: 80%;
/* Rounded top left corner */
border-top-left-radius: 15px;
-moz-border-radius-topleft: 15px;
-webkit-border-top-left-radius: 15px;
}
/* Fit the text nicely inside the box */
h1 {
font-family: sans-serif;
margin-bottom: 0;
}
#placeDetails p {
margin-top: 0;
}
</style>
Now we have a structure that we can wire up using jQuery. The first step is to make the window simply slide in and out in response to the click event on our placemark.
var currentPlace = null;
var info = $('#placeDetails');
google.maps.event.addListener(marker, 'click', function() {
if (currentPlace) {
info.animate({right: '-320px'});
currentPlace = null;
} else {
info.animate({right: '0'});
currentPlace = marker;
}
});
This is a great start, but we need to abstract it out somewhat if it is to scale to more than one placemark.
JSON to the rescue
Let’s add Southern Cross Station to the map, the other major rail hub in Melbourne. To do this we will separate our data from our code by moving the definition of a placemark out into a hash. This is always a good idea that leads to understandable and maintainable code.var places = [
{
"title": "Flinders St Station",
"description": "This is a pretty major train station.",
"position": [ -37.818078, 144.966811 ]
},
{
"title": "Southern Cross Station",
"description": "Did you know it used to be called Spencer St Station?",
"position": [ -37.818358, 144.952417 ]
}
]
var currentPlace = null;
var info = $('#placeDetails');
$(places).each(function() {
var place = this;
var marker = new google.maps.Marker({
position: new google.maps.LatLng(place.position[0], place.position[1]),
map: map,
title: place.title,
icon: 'http://google-maps-icons.googlecode.com/files/train.png'
});
google.maps.event.addListener(marker, 'click', function() {
$('h1', info).text(place.title);
$('p', info).text(place.description);
if (currentPlace == marker) {
info.animate({right: '-320px'});
currentPlace = null;
} else {
info.animate({right: '0'});
currentPlace = marker;
}
});
});
This is a neat extraction—it is now easy to see and add new places, as well as adapt to any extra meta-data that may be available (such as a phone number for the place). Being able to deal with arbitrary extra meta-data is a strength of this approach which is not easy to do using KML. Note how easy it is to change the title and description of the info window using the jQuery text
function.
The other benefit is that the underlying data for the map can now be served up from elsewhere, such as a server process generating JSON on the fly. Move the places array out into a new file places.json
(without the var places =
part), and we can fetch it easily with jQuery.
$.getJSON('places.json', function(places) {
$(places).each(function() {
// As above
});
});
You may have trouble running this part if you are testing directly off the filesystem due to ajax security policies. The easiest way around it is to serve up both files via a webserver, which is an easy one line if you have ruby installed, otherwise putting it under your apache www root may be comfortable for you.
ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd).start'
Finishing touches
You now have the framework needed to go forth and make your own pretty maps. For bonus points, we can clean up the user experience a bit. When you click one station, then click another, it is currently a bit … bland. There is also no indication on the map as to which marker is selected. Let’s slide the window out again before switching the data, and change over the icon of the currently selected item.var icons = {
'train': 'http://google-maps-icons.googlecode.com/files/train.png',
'train-selected': 'https://dl.dropbox.com/u/3120508/train-selected.png'
}
google.maps.event.addListener(marker, 'click', function() {
var hidingMarker = currentPlace;
var slideIn = function(marker) {
$('h1', info).text(place.title);
$('p', info).text(place.description);
info.animate({right: '0'});
}
marker.setIcon(icons['train-selected']);
if (currentPlace) {
currentPlace.setIcon(icons['train']);
info.animate(
{ right: '-320px' },
{ complete: function() {
if (hidingMarker != marker) {
slideIn(marker);
} else {
currentPlace = null;
}
}}
);
} else {
slideIn(marker);
}
currentPlace = marker;
});
Much nicer. That looks totally ace.
See the demonstration page. View source for the full code.
Protips
- Google Map Icons is a gold mine of icons you can use and adapt for your map. Do donate if you use them!
- If you really want to serve the JSON data across domains, look into JSONP.
- If you install the json gem under ruby, you get access to the
prettify_json.rb
script, which you can pipe json into to make it easy to read. - That one line ruby server is pretty much unkillable. My roundabout way is CTRL-Z to background it, then
ps | grep "ruby -rwebrick" | cut -d ' ' -f 1 | xargs kill -9
. Feel free to suggest a better way in the comments! - The Google Maps API documentation is really quite spectacular. Get comfortable with it.
Frequently Asked Questions on Embellishing Your Google Map with CSS3 and jQuery
How can I add custom overlays to my Google Map using CSS3 and jQuery?
Custom overlays can be added to your Google Map using CSS3 and jQuery by creating a new overlay class. This class should extend the google.maps.OverlayView class. You will need to implement three methods: onAdd(), draw(), and onRemove(). The onAdd() method is called when the overlay is added to the map. The draw() method is called each time the map viewport changes and is responsible for positioning the overlay on the map. The onRemove() method is called when the overlay is removed from the map.
How can I use CSS3 to style my Google Map?
CSS3 can be used to style your Google Map by applying styles to the div that contains your map. You can use CSS3 properties such as border-radius to create rounded corners, box-shadow to add a shadow effect, and transform to rotate or scale your map. You can also use CSS3 animations and transitions to create smooth, animated effects.
How can I use jQuery to interact with my Google Map?
jQuery can be used to interact with your Google Map by attaching event handlers to the map or to individual map elements. For example, you can use the click event to respond when the user clicks on the map, or the mouseover event to respond when the user hovers over a map element. You can use the google.maps.event.addListener method to attach event handlers.
How can I add markers to my Google Map?
Markers can be added to your Google Map by creating a new google.maps.Marker object and specifying the map and position properties. The position property should be a google.maps.LatLng object representing the geographic coordinates of the marker. You can also specify other properties such as title, icon, and animation to customize the appearance and behavior of the marker.
How can I add a custom control to my Google Map?
A custom control can be added to your Google Map by creating a new control div and adding it to the map’s controls array. The control div should contain the HTML elements that make up your control, and should be styled using CSS. You can use the google.maps.ControlPosition constants to specify the position of the control on the map.
How can I add a custom info window to my Google Map?
A custom info window can be added to your Google Map by creating a new google.maps.InfoWindow object and specifying the content and position properties. The content property should be a string containing the HTML content of the info window. The position property should be a google.maps.LatLng object representing the geographic coordinates of the info window.
How can I add a polyline or polygon to my Google Map?
A polyline or polygon can be added to your Google Map by creating a new google.maps.Polyline or google.maps.Polygon object and specifying the path property. The path property should be an array of google.maps.LatLng objects representing the vertices of the polyline or polygon. You can also specify other properties such as strokeColor, strokeOpacity, and strokeWeight to customize the appearance of the polyline or polygon.
How can I add a ground overlay to my Google Map?
A ground overlay can be added to your Google Map by creating a new google.maps.GroundOverlay object and specifying the url and bounds properties. The url property should be a string containing the URL of the image to be used as the overlay. The bounds property should be a google.maps.LatLngBounds object representing the geographic area covered by the overlay.
How can I add a KML layer to my Google Map?
A KML layer can be added to your Google Map by creating a new google.maps.KmlLayer object and specifying the url property. The url property should be a string containing the URL of the KML file. The KML file should be publicly accessible on the web.
How can I add a Street View panorama to my Google Map?
A Street View panorama can be added to your Google Map by creating a new google.maps.StreetViewPanorama object and specifying the div and position properties. The div property should be the div that will contain the panorama. The position property should be a google.maps.LatLng object representing the geographic coordinates of the panorama.
Xavier Shay is a DataMapper committer who has contributed to Ruby on Rails. He wrote the Enki blog platform, as well as other widely used libraries, including TufteGraph for JavaScript graphing and Kronic for date formatting and parsing. In 2010, he traveled the world running Ruby on Rails workshops titled "Your Database Is Your Friend." He regularly organizes and speaks at the Melbourne Ruby on Rails Meetup, and also blogs on personal development at TwoShay, and on more esoteric coding topics at Robot Has No Heart.