Feb 10 2010

Google Map: évènement sur un polygone et carte de France cliquable

Résumé

La méthode habituelle pour ajouter un polygone dans une Google Map est d'utiliser un fichier KML. En utilisant cette méthode il n'est pas possible de capturer un évènement sur une placemark et donc, a fortiori, sur un polygone.
Cet article expose deux méthodes pour capturer un événement sur un polygone dans une Google Map et se termine en proposant le code JavaScript qui permet de créer une belle et légère Google Map cliquable des régions et départements français généré par l'API PHP pi-google-maps-api que je développe.

Méthodes utilisant du « XML Parsing » en JavaScript

La méthode la plus classique consiste à utiliser conjointement les fonctions GDownloadUrl et GXml. L'évènement à proprement parlé se capture avec la fonction GEvent.addListener.

  • GDownloadUrl offre un moyen pratique de récupérer de manière asynchrone une ressource identifiée par une adresse locale. Son utilisation est plus simple que la routine native XmlHttpRequest() mais elle hérite des mêmes restrictions ;
  • GXml est une classe JavaScript composée de deux méthodes statiques qui permettent de manipuler du XML sous forme de DOM.

Concrètement cela se traduit par le code suivant:

var map;
function load() {
    if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("amap"));
        map.setCenter(new GLatLng(43.2126053,2.3560999),8);
        map.setUIToDefault();

        GDownloadUrl(
            "contour11.xml",
            function(data, responseCode) {
                var xmlData = GXml.parse(data);
                var coords = xmlData.documentElement.getElementsByTagName("coordinate");
                var coordinates = new Array();
                for (var i = 0; i < coords.length; i++) {
                    coordinates[i] = new GLatLng(parseFloat(coords[i].getAttribute("y")),
                                                 parseFloat(coords[i].getAttribute("x")));
                }
                coordinates[i+1] = coordinates[0];
                polygons = new google.maps.Polygon(coordinates,
                                                   "#000000", 0.5, 1, "#aa6ecd", 0.2);
                map.addOverlay(polygons);
                GEvent.addListener(polygons,"click",
                                   function(){
                                       alert('Vous avez cliqué sur le département de l\'Aude');
                                   });
            }
        );
    }
}
  

Voici le résultat, sans surprise, un clique sur le polygone ouvre une boîte d'alerte:

Cette méthode est simple mais a deux inconvénients majeurs:

  • Il y a autant de requêtes HTTP que de polygones à tracer et cela peut consommer beaucoup de ressource serveur ; on peut facilement contourner cet inconvénient en mettant tous les polygones dans un seul fichier mais cela reste imparfait si l'on veut parfois tracer un seul polygone, parfois les tracer tous.
  • Imaginons que l'on veuille ajouter un bouton qui permette d'implémenter une bascule Cacher/Afficher le polygone ; comment faire référence à l'instance du polygone (variable polygon dans le code précédent) ?
    Ce n'est tout simplement pas possible car le code placé après la fonction GDownloadUrl sera exécuté avant que les données ne soient récupérées et donc que le fonction anonyme passée en paramètre à GDownloadUrl ne soit exécuté. Une possibilité serait d'utiliser la notion de clôsure en encapsulant tout le code dans une « sur-routine » mais j'ai comme un gros coup de flemme pour tester cette idée et je ne suis pas certain que ce soit portable.

Le deuxième inconvénient soulevé précédemment peut être contourné en utilisant la bibliothèque EGeoXml ou mieux GeoXML mais je trouve que c'est assez lourd d'utilisation. Un exemple se trouve ICI ; mais, pour moi, c'est inutilisable, trop lent, trop lourd et pas assez précis/propre.

Méthode post « XML Parsing »

Rien d'originale, il suffit de « parser » le fichier xml ou kml avec le script de votre choix pour générer les variables JavaScript qui vont bien. Pour ma part j'ai choisi d'utiliser des tableaux associatifs d'objets JSON :

polygons["polygonXX"]={
    "coords":[[47.58363344,-2.98932],[47.58806266,-2.99573427],ETC…],
    "fillStyle":{color:'#FFAA88',opacity:0.2},
    "strokeStyle":{color:'#000000',opacity:0.5,weight:2},"visible":true};
  

Je ne vous laisse pas attendre d'avantage pour contempler le résultat et cliquer/survoler sur les départements:

On peut explorer le code source de cet exemple ICI.

Une Google Map cliquable des régions et des départements de France

Sur ce principe, j'ai implémenté dans l'api php pi-google-maps-api, que j'ai développée, des méthodes simples qui permettent d'automatiser la génération de telles cartes.
Je vous laisse explorer les exemples de l'api:

3 Responses to “Google Map: évènement sur un polygone et carte de France cliquable”

Flux RSS de ces commentaires rss

  1. manirakiza franck says:

    Je suis entrain d'essayer de trouver le moyen de récupérer un Click sur un polygone dessiné sur une carte. Je trouve votre API très intéressante. Mais comment arriver à l'utiliser? Merci pour vos éclaircissements.

    • AdminPh. Ivaldi says:

      La documentation est effectivement assez…succincte.
      Pour utiliser cette API, il suffit de copier les sources PHP sur votre serveur et d'affecter à la constante GMA_PATH, du fichier GoogleMapsAPI.class.php, le chemin absolu (pas l'url) du répertoire où vous avez installé GoogleMapsAPI.class.php.
      C'est tout, les exemples devraient fonctionner et je vous laisse les adapter à vos besoins.

  2. inetis says:

    Merci pour cet excellent article :)
    Si je reprends l'exemple de des régions et départements de France. Comment faire pour éviter le changement de page entre régions et département ? Est ce que c'est imaginable qu'en cliquant sur la région, on arrive sur la carte du département dans la même map ?
    J'ai vu que qu'avec le KML et l'api Google on peut définir des niveaux de zoom pour les objets (définir à partir de quel niveau de zoom un objet s'affiche). Est ce qu'on peut combiner cette propriété avec votre class ?