Google Maps API v3 : utilisation de multiples InfoWindows et zoom

Aujourd'hui, j'ai essayé de jouer un petit peu avec l'API Maps v3 de Google. Dans le cadre d'un projet personnel (relié à un article précédent sur les coordonnées GPS dans les photos et les problèmes de vie privée), j'aimerais afficher plusieurs informations sur une carte. Le but est d'avoir plusieurs marqueurs, et de pouvoir cliquer sur ces marqueurs afin de pouvoir faire afficher les données qu'ils contiennent, comme dans l'exemple ci dessous :

info Windows HTML

Un exemple d'infoWindows, qui permet d'afficher un texte en HTML.

Une autre contrainte est de proposer un zoom le plus adapté possible, c'est-à-dire une carte avec le plus de précision possible qui permette de voir tous les marqueurs.

Dans ce billet, je vais faire un retour sur ces deux étapes. Le code source final (free as freespeech/beer) est accessible sur GitHub, et vous pouvez voir le résultat ici.

Le cas des multiples markers et infoWindows

La documentation de l'API v3 de Maps fournit de nombreux exemples, mais malheureusement pas d'explications sur ce que je souhaitais obtenir, à savoir les multiples fenêtres infoWindows. Une partie de la complexité est de trouver des exemples sur la bonne version de l'API : en effet, depuis l'API v2,  de nombreux changements ont eu lieu, et de nombreux tutoriels sont donc dépassés et/ou utilisent jQuery pour charger les points, rajoutant une complexité et des calculs inutiles ; tout peut être fait directement avec l'API Google.

Stockage des points (et zIndex)

J'ai stocké les points sous forme de tableau javascript, voilà une version expurgée (la version totale exploite les possibilités HTML de l'infoWindows) :

var sites = [
['Darlington', -35.0252820, 138.5630230, 1, 'Darlington, where I am living.'],
['Flinders', -35.0188300, 138.5731367, 2, 'Flinders, where I study'],
['Glenelg Beach', -34.9803618, 138.5097885, 1, 'Glenelg Beach, no comment.'],
['Hindley Street', -34.9232880, 138.5935256, 1,'Hindley Street, a pub dedicated street.']
];

Le premier paramètre est le titre du point, suivi de la latitude, la longitude, le zIndex et le contenu HTML qui sera affiché. Le zIndex sert a établir quel sera la fenêtre affiché au dessus des autres si il y a un chevauchement. Dans notre cas, cela ne risque pas de se produire, mais Flinders et Darlington étant quand même relativement près l'un de l'autre, je leur ai mis un zIndex différent (on notera que j'ai mis la priorité sur les cours).

Affichage sur la carte

Voici la fonction qui est appelée pour afficher tous les points sur la carte ; la première partie est basée sur le code d'ajout de multiples markers fourni par les exemples de Google. Les markers sont construit à partir des données précédentes. La seule chose digne d'intéret est le animation: google.maps.Animation.DROP qui permet de faire "tomber" et rebondir le marqueur lors de son arrivée sur la carte. Pour observer de manière certaine ce comportement, recharger la page de la démo : le fait que les tiles soient déjà en cache permet de voir en entier ce comportement.

function setMarkers(map, markers) {
	for (var i = 0; i < markers.length; i++) {
		var site = markers[i];
		var siteLatLng = new google.maps.LatLng(site[1], site[2]);

		var marker = new google.maps.Marker({
			position: siteLatLng,
			map: map,
			title: site[0],
			zIndex: site[3],
			html: site[4],
			// Markers drop on the map
			animation: google.maps.Animation.DROP
		});

		google.maps.event.addListener(marker, "click", function () {
			infowindow.setContent(this.html);
			infowindow.open(map, this);
		});
	}
}

La deuxième partie est celle qui associe chaque marqueur à sa fenêtre ; c'est un peu contre intuitif car on perd la référence sur le marker, ce qui peut être limitant (par exemple changer le comportement associé au marker dans la suite du code), mais je n'ai pas trouvé d'autres solutions et la documentation ne contient pas d'exemple.

Zoom adapté

Maintenant que nous avons réussi a mettre tous nos points (et toutes nos petites bulles) dans la meme carte, on peut avoir envie de la mettre en forme dans l'écran de l'utilisateur pour que :

  1. Elle soit centrée à un endroit pertinent (au milieu des points par exemple) ;
  2. Le zoom permette de voir tous les points sans pourtant donner une vision de l’Antarctique (un mix entre ça et ça, les niveaux de zoom sont compris entre 1 et 22).

Deux approches sont possibles ; développer sa propre fonction, ce qui permet de centrer la carte précisément ou on veut (par exemple au barycentre des points, et non pas au milieu créé en tenant compte des points les plus éloignés). La solution de simplicité est clairement le milieu :

function setZoom(map, markers) {
	var boundbox = new google.maps.LatLngBounds();
	for ( var i = 0; i < markers.length; i++ )
	{
	  boundbox.extend(new google.maps.LatLng(markers[i][1], markers[i][2]));
	}
	map.setCenter(boundbox.getCenter());
	map.fitBounds(boundbox);
}

Cette solution repose sur l'utilisation d'un composant LatLngBound qui est très pratique à utiliser ; il suffit de lui soumettre les points, et cette boite permet ensuite de définir le centre théorique de la carte, et le niveau de zoom adapté pour une lecture confortable.

Si vous choisissez de créer votre propre fonction (ce que j'ai fait car je n'avais pas vu ce point de la documentation), vous vous engagez dans une voie assez complexe, qui sera parsemée de calculs trigonométriques pour faire intervenir la courbure de la Terre et calculer les distances entre les points. De plus, la correspondance entre une zone définie par sa taille et ses bornes et un niveau de zoom est relativement complexe.

Cadrage du Zoom Google Maps

Comment placer le point central et le définir le zoom simplement ?

En plus, une réflexion sur la zone de confort nécessaire à la lecture autour de chaque marqueur est nécessaire, et contribue à rajouter quelques lignes au calcul. Aussi je vous conseille chaudement d'utiliser la fonction par défaut, qui m'a bien manquée pendant quelques heures.

Bonus

Je pense que vous continuerez a entendre parler des maps Google sur ce blog dans les prochains jours / prochaines semaines. En attendant, si cela vous intéresse particulièrement ou que vous avez des questions, n'hésitez pas jeter un oeil au code source en entier, me contacter via les commentaires ou Twitter.

Vous pouvez utiliser le code fourni, ça me ferait même plaisir de savoir que je ne l'ai pas remis en forme pour rien !

Comme vous l'avez sans doute remarqué, les exemples sont Australie-centriques ; si cela vous intéresse, vous pouvez jeter un oeil à quelques unes des photos que j'ai pu y faire sur mon compte Flickr.

Vus : 5393
Publié par Romain Bochet : 29