Carte Google Map à la volée avec jQuery

Publié le

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.