nyroBlog
Bannière NyroBlog, par Jean-François
Image par Jean-François - ?

Tag : Google


Google Map on demand with jQuery

It's pretty common to embed a map on a contact page. But you want this map only on this page. So you don't need to load the Google Map API on every page of your site

Coupled with adress microdata (which you should already have in place), it becomes easy to load a google map on demand with a marker to the desired address.

1. Load Google Map

To load google map is simple. Just call in the URL of the Ajax API. But we must ensure proper load and execute the following script when it's completly loaded. Otherwise, you call functions that doesn't exist on the page.

A simple callback on the load of the script isn't sufficient because Google actually loads an other JS file, corresponding to the current Google Map API version.

I you readSi the doc, you understand you can add a callback that will be called by the APi once loaded

We'll write a function to load this JS file and add a callback given as a parameter. A small addition will permit to load it only one time.

var gmapUrl = 'http://maps.google.com/maps/api/js?sensor=false',
	gmapLoaded = false,
	loadGmap = function(clb) {
		if (!gmapLoaded) {
			window.gMapClb = function() {
				window.gMapClb = null;
				gmapLoaded = true;
				clb();
			};
			$.ajax({url: gmapUrl+'&callback=gMapClb', dataType: 'script'});
		} else {
			clb();
		}
	};

We can now dynamically load the Google Map API and execute a function when everything has come up.

2. Read microdata

The purpose of the code we're writing is to be called on a container, find Address microdata and display the corresponding map.

Once the address is found, we will use geocode from Googme Map to locate the map and add a marker.

Reading microdata is pretty easy thanks to jQuery. We're adding every element in an array:

var adr = me.find('[itemtype="http://data-vocabulary.org/Address"]');
if (adr.length) {
	var search = [],
		elm;
	$.each(['street-address', 'postal-code', 'locality', 'region', 'country-name'], function() {
		elm = adr.find('[itemprop="'+this+'"]');
		if (elm.length)
			search.push(elm.text());
	});
}

Once the address is on the search Array, it only remains to call the geocoder to find its location.

3. Locate address and show the map

We've got the address. We can load the Google Map API on demand with a callback. We still have to find the address location. And if we have it, show the map. To search it, I won't discuss here all the details of Geocoder.

When getting a result from geocoder, a div[class=map] is append to the containing element and the Google Map instance will be created on it. It's the CSS duty to positionnate this div and giving it a height and width.

To allow a toffle of this map, we will save a reference of the map container, a reference of the Google map and the location of the result. A marker is automaticall added at the result location.

loadGmap(function() {
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({address: search.join(', ')}, function(results, status) {
		if (results.length && status == google.maps.GeocoderStatus.OK) {
			var map = $('<div class="map" />').appendTo(me),
				GMap = new google.maps.Map(map.get(0), {
					center: results[0].geometry.location,
					mapTypeId: google.maps.MapTypeId.ROADMAP,
					zoom: defaultZoom
				});
			new google.maps.Marker({
				map: GMap,
				visible: true,
				position: results[0].geometry.location
			})
			me.data('gmap', {
				map: map,
				GMap: GMap,
				location: results[0].geometry.location
			});
		}
	});
});

Note the defaultZoom variable defined elsewhere. (required to create a map)

 

4. Put it all together

We have the 3 necessary elements to view the map. Let's put that in a jQuery plugin, add functionnality to hide/show it on each call of this plugin and we get this:

$(function() {
	var defaultZoom = 15,
		gmapUrl = 'http://maps.google.com/maps/api/js?sensor=false',
		gmapLoaded = false,
		loadGmap = function(clb) {
			if (!gmapLoaded) {
				window.gMapClb = function() {
					window.gMapClb = null;
					gmapLoaded = true;
					clb();
				};
				$.ajax({url: gmapUrl+'&callback=gMapClb', dataType: 'script'});
			} else
				clb();
		};
	
	$.fn.extend({
		myGmap: function() {
			return this.each(function() {
				var me = $(this);
				if (!me.data('gmap')) {
					var adr = me.find('[itemtype="http://data-vocabulary.org/Address"]');
					if (adr.length) {
						var search = [],
							elm;
						$.each(['street-address', 'postal-code', 'locality', 'region', 'country-name'], function() {
							elm = adr.find('[itemprop="'+this+'"]');
							if (elm.length)
								search.push(elm.text());
						});
						if (search.length) {
							loadGmap(function() {
								var geocoder = new google.maps.Geocoder();
								geocoder.geocode({address: search.join(', ')}, function(results, status) {
									if (results.length && status == google.maps.GeocoderStatus.OK) {
										var map = $('<div class="map" />').appendTo(me),
											GMap = new google.maps.Map(map.get(0), {
												center: results[0].geometry.location,
												mapTypeId: google.maps.MapTypeId.ROADMAP,
												zoom: defaultZoom
											});
										new google.maps.Marker({
											map: GMap,
											visible: true,
											position: results[0].geometry.location
										})
										me.data('gmap', {
											map: map,
											GMap: GMap,
											location: results[0].geometry.location
										});
									}
								});
							});
						}
					}
				} else {
					me.data('gmap').map.fadeToggle(function() {
						if (me.data('gmap').map.is(':not(:visible)')) {
							me.data('gmap').GMap.setZoom(defaultZoom);
							me.data('gmap').GMap.panTo(me.data('gmap').location);
						}
					});
				}
			});
		}
	});
});

When the map is hidden, the map is centered again and the default zoom is resset to the default value.

Enjoy!

Version française de ce billet.

Carte Google Map à la volée avec jQuery

Il n'est pas rare de vouloir intégrer une carte sur une page contact d'un site. Mais on ne veut afficher une carte uniquement sur cette page. C'est donc dommage de charger le javascript de Google Map sur toutes les pages.

Couplé à des micro-data d'adresse (que vous devriez déjà avoir mis en place), il devient facile de charger une carte google à la volée avec un marker à l'adresse désirée.

1. Charger Google Map

Pour charger google map, c'est simple. Il suffit d'appeler en Ajax l'URL de l'API. Mais il faut aussi s'assurer de son bon chargement et n'exécuter la suite du script que lorsqu'il est complètement chargé. Sinon, on se retrouve à appeler des fonctions qui n'existent pas encore sur la page.

Un simple callback sur le chargement du script ne suffit pas puisque Google charge encore un autre fichier JS qui correspond en réalité à la dernière version de l'API.

Si l'on lit la doc, on comprend que l'on peut ajouter un callback que l'API appelera une fois chargée.

Nous allons donc écrire une fonction pour charger le fichier JS et appeler un callback donné en paramètre lorsque celle sera en place. Un petit ajout permettra de ne charger qu'une seule fois si on exécute plusieurs la fonction :

var gmapUrl = 'http://maps.google.com/maps/api/js?sensor=false',
	gmapLoaded = false,
	loadGmap = function(clb) {
		if (!gmapLoaded) {
			window.gMapClb = function() {
				window.gMapClb = null;
				gmapLoaded = true;
				clb();
			};
			$.ajax({url: gmapUrl+'&callback=gMapClb', dataType: 'script'});
		} else {
			clb();
		}
	};

On peut donc maintenant charger dynamiquement l'API de Google Map, et exécuter un code lorsque tout est arrivé.

2. Lire le micro-format

Le but du code que nous sommes en train d'écrire permettra d'être appelé sur un bloc contenant, de chercher le micro-format d'adresse et d'afficher la carte correspondante.

Une fois les informations de l'adresse trouvées, nous l'utiliserons avec le geocoder de Google Map pour positionner la carte et ajouter le marker.

La lecture du mirco-format est hyper simple, on met chacun des éléments à la suite dans un tableau :

var adr = me.find('[itemtype="http://data-vocabulary.org/Address"]');
if (adr.length) {
	var search = [],
		elm;
	$.each(['street-address', 'postal-code', 'locality', 'region', 'country-name'], function() {
		elm = adr.find('[itemprop="'+this+'"]');
		if (elm.length)
			search.push(elm.text());
	});
}

Une fois cette adresse complétée dans le tableau search, il ne restera plus qu'à appeler le geocoder pour chercher cette adresse.

3. Chercher l'adresse et afficher la carte

Nous avons l'adresse. Nous savons charger la Google Map API à la volée avec un callback. Il ne reste plus qu'à chercher l'adresse, et si l'on trouve, affiché cette carte. Pour la recherche d'adresse, je ne détaillerai pas ici les détails du Geocoder.

Au résultat du geocoder, on ajouter une div[class=map] à l'élément contenant et l'instance de la carte Google sera créée dans cette div. Charge à la CSS du site de positionner cette div, en lui donnant une hauteur et largeur adequat.

Pour permettre un toggle de cette map, on enregistrera dans une data la référence du conteneur de la carte, la référence de la carte et la position du résultat. Le marker est automatiquement ajouté à l'emplacement du résultat.

loadGmap(function() {
	var geocoder = new google.maps.Geocoder();
	geocoder.geocode({address: search.join(', ')}, function(results, status) {
		if (results.length && status == google.maps.GeocoderStatus.OK) {
			var map = $('<div class="map" />').appendTo(me),
				GMap = new google.maps.Map(map.get(0), {
					center: results[0].geometry.location,
					mapTypeId: google.maps.MapTypeId.ROADMAP,
					zoom: defaultZoom
				});
			new google.maps.Marker({
				map: GMap,
				visible: true,
				position: results[0].geometry.location
			})
			me.data('gmap', {
				map: map,
				GMap: GMap,
				location: results[0].geometry.location
			});
		}
	});
});

On remarquera la variable defaultZoom défini ailleurs. (indispensable pour la création d'une map)

 

4. On assemble le tout

On a les 3 éléments indispensable pour afficher cette carte. Mettons tout ceci dans un plugin jQuery, ajoutons la fonctionnalité de caché/affiché la carte à chaque appel de ce plugin et nous obtenons ceci :

$(function() {
	var defaultZoom = 15,
		gmapUrl = 'http://maps.google.com/maps/api/js?sensor=false',
		gmapLoaded = false,
		loadGmap = function(clb) {
			if (!gmapLoaded) {
				window.gMapClb = function() {
					window.gMapClb = null;
					gmapLoaded = true;
					clb();
				};
				$.ajax({url: gmapUrl+'&callback=gMapClb', dataType: 'script'});
			} else
				clb();
		};
	
	$.fn.extend({
		myGmap: function() {
			return this.each(function() {
				var me = $(this);
				if (!me.data('gmap')) {
					var adr = me.find('[itemtype="http://data-vocabulary.org/Address"]');
					if (adr.length) {
						var search = [],
							elm;
						$.each(['street-address', 'postal-code', 'locality', 'region', 'country-name'], function() {
							elm = adr.find('[itemprop="'+this+'"]');
							if (elm.length)
								search.push(elm.text());
						});
						if (search.length) {
							loadGmap(function() {
								var geocoder = new google.maps.Geocoder();
								geocoder.geocode({address: search.join(', ')}, function(results, status) {
									if (results.length && status == google.maps.GeocoderStatus.OK) {
										var map = $('<div class="map" />').appendTo(me),
											GMap = new google.maps.Map(map.get(0), {
												center: results[0].geometry.location,
												mapTypeId: google.maps.MapTypeId.ROADMAP,
												zoom: defaultZoom
											});
										new google.maps.Marker({
											map: GMap,
											visible: true,
											position: results[0].geometry.location
										})
										me.data('gmap', {
											map: map,
											GMap: GMap,
											location: results[0].geometry.location
										});
									}
								});
							});
						}
					}
				} else {
					me.data('gmap').map.fadeToggle(function() {
						if (me.data('gmap').map.is(':not(:visible)')) {
							me.data('gmap').GMap.setZoom(defaultZoom);
							me.data('gmap').GMap.panTo(me.data('gmap').location);
						}
					});
				}
			});
		}
	});
});

Lorsqu'on cache la carte, on en profite pour recentrer la map et remettre le niveau de zoom à celui paramétré par défaut.

Enjoy!

English version of this post.

Do you know Roger Hargreaves?

So do I... until this morning when I saw the new Doodles.

Roger Hargreaves, he's the illustrator and creator of the well known seriesof Mr. Men and Little Miss that we all already read..

That's a total of 16 Doodles created especially for the event by Google:

 

Roger Hargreaves, Doodle 1
Roger Hargreaves, Doodle 2
Roger Hargreaves, Doodle 3
Roger Hargreaves, Doodle 4
Roger Hargreaves, Doodle 5
Roger Hargreaves, Doodle 6
Roger Hargreaves, Doodle 7
Roger Hargreaves, Doodle 8
Roger Hargreaves, Doodle 9
Roger Hargreaves, Doodle 10
Roger Hargreaves, Doodle 11
Roger Hargreaves, Doodle 12
Roger Hargreaves, Doodle 13
Roger Hargreaves, Doodle 14
Roger Hargreaves, Doodle 15
Roger Hargreaves, Doodle 16

 

Which one do you prefer?

Roger Hargreaves, vous connaissez ?

Hé bien moi non plus, jusqu'à ce matin en voyant les doodle de Google.

Roger Hargreaves, c'est l'illustrateur et créateur de la série des Monsieurs/Madames qu'on connaît tous.

C'est pas moins de 16 Doodles créés juste pour l'occasion par google :

 

Roger Hargreaves, Doodle 1
Roger Hargreaves, Doodle 2
Roger Hargreaves, Doodle 3
Roger Hargreaves, Doodle 4
Roger Hargreaves, Doodle 5
Roger Hargreaves, Doodle 6
Roger Hargreaves, Doodle 7
Roger Hargreaves, Doodle 8
Roger Hargreaves, Doodle 9
Roger Hargreaves, Doodle 10
Roger Hargreaves, Doodle 11
Roger Hargreaves, Doodle 12
Roger Hargreaves, Doodle 13
Roger Hargreaves, Doodle 14
Roger Hargreaves, Doodle 15
Roger Hargreaves, Doodle 16

Quel est votre préféré ?

Google Wave Invitations

You may have heard about Google Wave these days. It's THE new communication tool which will try to replace email and instant messaging in the same time in a future not so near for me.

I'll write a post about ir soon to give my opinion and some ideas about the way we could use it.

But here is not the point.

I've got some new invitations this morning for Google Wave.

So, I propose you a thing pretty easy and usual for this kind of thing: A simple comment with a valid email address will let you participate to a lottery to win your Google Wave invitation. There will be 5 invitations to win.

The comment should be sent before Friday, the 13rd 2009.

I'll then edit this post to indicate the winner.

In the mean time, if you want to share your idea about it and what it could become, don't hesitate !

And the winners are:

  • Bastien
  • Jonas
  • Nico
  • aminoux
  • Martin