11 décembre 2012

Une heatmap dynamique en JavaScript/HTML5



L'analyse spatiale passe par l'usage d'outils plus ou moins complexes, mais le premier outil que nous utilisons sans même nous en rendre compte est l’œil. La lecture d'une carte donne instantanément des renseignements tels que : la localisation d'une infrastructure ou d'un évènement, la répartition spatiale de ces évènements, leur nature, etc... La vitesse de cette analyse dépend en grande partie de la représentation cartographique choisie.

Lorsque vous affichez des couches de points sur une carte et diffusez cette carte sur le web, se pose donc la question du mode de représentation.
Pour un volume de données réduit et une répartition spatiale peu dense, une bonne sélection du symbole, de sa taille et de la plage de visibilité de la couche permettront d'assurer une bonne lisibilité de la carte.

En revanche lorsque le volume de donnée (nombre de points) augmente ou que leur répartition spatiale est dense la carte devient illisible et difficilement exploitable à l'œil.

Afin d'optimiser l'affichage d'une couche ponctuelles volumineuse, deux types de symbologie s'offrent à nous:
  • la symbologie sous forme d'agrégat (clustering), déjà disponible dans les API Web d'ArcGIS for Server (Silverlight, Flex, JavaScript).
  • la représentation de type carte de densité (ou carte de points chauds) (heatmap).
C'est cette dernière qui nous intéresse aujourd'hui.

Qu'est-ce qu'une heatmap?

De manière générale une heatmap est une représentation graphique des données employant des couleurs pour indiquer le degré d'activité ou la fréquence d'apparition de la donnée, en générale des couleurs froides pur indiquer une faible densité et plus chaudes pour indiquer une densité forte.

Les heatmap sont utilisées dans différents domaines comme par exemple l'ergonomie et le web marketing il pour étudier le temps et les zones de fixation du regard sur une page web ou un e-mail. (plus de détails ici), et bien sûr dans le domaine des SIG.

Dans le domaine de la géographie, il s'agit donc d'une méthode de représentation des données en fonction de leur densité spatiale.

Si vous souhaitez ajouter une heatmap dans vos applications web cartographiques, deux options sont possibles :
  • pré-calculer la heatmap avec ArcGIS for Dekstop, publier le résultat sous forme de service web MapService) et ajouter le MapService dans la carte.
  • offrir un outil dynamique à votre application web. Si les données ponctuelles sont mises à jour la heatmap s'adaptera automatiquement

La librairie heatmap.js

Nous allons voir ici comment assurer cette fonctionnalité de génération de heatmap à la volée dans une application web JavaScript, grâce à une librairie open source crée par Patrick Wied.


La librairie heatmap.js est une librairie JavaScript qui exploite les Canvas HTML5 afin d'afficher des heatmap au rendu fort appréciable dans votre appli web. La Heatmap est calculé côté client (navigateur) et ne requiert aucun plugin. Le seul pré requis étant que le navigateur supporte les Canvas HTML5 (ce que font les navigateurs récents, y compris sur les périphériques mobiles). Cette librairie est sous licence  opensource de type MIT and the Beerware license, vous êtes donc libres de l'utiliser. Elle est également disponible sur github, vous pouvez donc faire remonter vos impressions et remarque auprès de son concepteur, mais également contribuer à son évolution.


Son principe de fonctionnement est le suivant : la heatmap est générée dynamiquement d'après vos données ponctuelles qui peuvent provenir d'une couche graphique (que vous aurez pris soin de remplir par une requête par exemple). vous pouvez donc mettre à profit les featureLayers de l'ArcGIS API for JavaScript (qui sont assimilables à des graphicsLayers remplis automatiquement par une requête pré-définie).


La heatmap se base sur cette collection de points. A chaque fois qu'un point est ajouté à la collection, un processus vérifie si la valeur maximum a changé et appelle une fonction de dessin du gradient de couleur (qui est fonction des valeurs min et max de la collection).


Si par exemple la collection en contient qu'un seul point, il sera afficher avec la plus forte valeur. Si un nouveau point y est ajoutées, les valeur min et max seront recalculée dynamiquement, donc le gradient aussi, donc la heatmap est mise à jour. La heatmap ajoutée par code à votre application web est entièrement personnalisable en terme de gradient de couleur, transparence, rayon de calcul etc...

Ajout d'une heatmap dynamique à votre application web

Partons d'une application très simple contenant une carte. Cette carte est constituée d'une basemap (par exemple la World Topo Map Esri).


Dans l'ordre, il faut d'abord inclure les librairies JavaScript nécessaires : heatmap.js (qui permet d'afficher une heatmap à partir d'un tableau de points) et heatmap-arcgis.js (qui  permet de faire le lien entre cette librairie heatmap.js et l'ArcGIS API for JavaScript).

Nous avons ensuite besoin de définir l'élément HTML qui contiendra le fameux HTML Canvas d'HTML5 crée à la volée par la librairie heatmap.js.

<div id=”heatLayer”></div> 

A présent nous pouvons créer, via la partie Javascript de notre page HTML, la heatmap en spécifiant le rayon de traitement, le gradient de couleur, la transparence. Un paramètre (useLocalMaximum) permet également de spécifier la manière dont la valeur maximun est calculées : soit en tenant compte de l'ensemble des données de la couche ponctuelle, soit en tenant compte uniquement des données visibles dans l'étendue affichée. 

heatLayer = new HeatmapLayer({

                        config: {

                            "useLocalMaximum": true,

                            "radius": 40,
                            "gradient": {
                                0.45: "rgb(000,000,255)",
                                0.55: "rgb(000,255,255)",
                                0.65: "rgb(000,255,000)",
                                0.95: "rgb(255,255,000)",
                                1.00: "rgb(255,000,000)"
                            }
                        },
                        "map": map,
                        "domNodeId": "heatLayer",
                        "opacity": 0.85
                    });

Le paramètre domNodeId doit avoir pour valeur le nom de l'élément HTML qui accueillera la heatmap.
N'oublions pas d'ajouter cette nouvelle couche à la carte : map.AddLayer(heatLayer);

Tout est prêt, il suffit à présent de remplir la couche.
Comment remplir notre heatLayer? A vous de choisir, mais un moyen simple est de réaliser une requête au serveur ArcGIS puis de "câbler" le résultat de cette requête sur la heatLayer.
Nous avons choisi ici d'utiliser des données référencées sur le portail OpenGeoData.fr : la couche des arrêts du réseau de transport en commun de la région Bordelaise (détails ici : http://www.opengeodata.fr/home/item.html?id=6a59850d794e46ab9af9df2cdb275246)


La couche de points que nous souhaitons afficher sous forme de heatmap est également affichée dans la carte sous forme de featureLayer.

Pour rappel, une featureLayer dérive des graphicsLayer. Une graphicsLayer permet de gérer côté client , donc localement dans votre navigateur, des objets graphiques (géométrie + attributs + symbologie) et de les afficher sur la carte. Une featureLayer est une graphicsLayer avec un comportement particulier qui est de se remplir quasi automatiquement. Elle possède pour cela une url (l'url d'un service de carte dynamique ou d'un service d'entités ArcGIS for Server, ou bien enfin d'une service d'entités hébergé sur ArcGIS Online). Une fois cette featureLayer ajoutée à la map, elle sera remplie via une requête sur le service web associé.
Notre featureLayer est en mode "ondemand", c'est à dire que seuls les points contenus dans l'étendue d'affichage sont stockés localement après requête au serveur. A chaque fois que l'étendue est mise à jour, la requête est automatiquement exécutée et la couche remplie.

Nous allons donc procéder de la même manière pour la heatLayer, ce qui nous permettra d'assurer le côté dynamique. A chaque fois qu'un point est ajouté à la featureLayer, il devra être ajouté à la heatLayer pour que la heatmap soit mise à jour (gradient recalculé, etc...).

Nous définissons donc une fonction getFeature() qui se chargera de faire la requête auprès du server, et d'envoyer le résultat (les points) à la heatLayer. Cette fonction sera appelée à chaque fois que l'étendue de la carte est mise à jour. donc on lie cette fonction à l'évènement onExtentChange de l'objet map. 

function getFeatures() {

                // la requête

                var query = new esri.tasks.Query();

                // seulement pour l'étendue

                query.geometry = map.extent;

                // on veut uniquement les arrêts de la commune de Bordeaux
                query.where = "ville = 'BORDEAUX'";              
                query.outSpatialReference = map.spatialReference;
                // on execute la requête
                featureLayer.queryFeatures(query, function (featureSet) {
                    var data = [];
                    // s'il y a un résultat
                    if (featureSet && featureSet.features && featureSet.features.length > 0) {
                        // on met le résultat dans un objet data
                        data = featureSet.features;
                    }
                    // que l'on envoie à notre heatLayer
                    heatLayer.setData(data);
                });
            }

puis :

dojo.connect(map, "onExtentChange", getFeatures);



 
Simple, efficace, rapide et beau.


Libre à vous d'adapter le code pour offrir plus de fonctionnalités à l'utilisateur final (comme par exemple une belle interface afin de définir le gradient de couleurs, le rayon d'analyse, la couche à laquelle la heatmap est associée, etc...).
En conclusion, cette fonctionnalité se retrouve dans toutes les API web ArcGIS puisque c'est aussi possible en Silverlight et Flex. 

Vous avez donc vu ici comme grâce à cette librairie, vous pouvez enrichir votre application web JavaScript avec une heatmap dynamique en quelques lignes de codes et surtout l'exploiter sur votre navigateur web ou sur votre smartphone ou tablet tactile préférée.

Les heatmap dynamiques sont donc à la portée de tous.

L'application est visible ici.
Le code source d'exemple est  téléchargeable ici. 

Aucun commentaire: