Un des principaux points apportés par l’API AJAX V7 de la plateforme Bing Maps for Enterprise est sa capacité à pouvoir être étendu afin d’apporter de nouvelles fonctionnalités que ce soit à travers des modules dynamiques ou tout simplement pour améliorer ou compléter les éléments de base.

Bing Maps extensions et modules AJAX v7

L’extension, pourquoi et comment ?

Le principe d’extension est un des fondamentaux du langage JavaScript et permet d’ajouter des propriétés ou méthodes sur des objets définis voir même de remplacer directement un comportement par un autre de manière totalement dynamique.Extension de Bing Maps ajax v7 HTML5 et module dynamique

Le contrôle AJAX v7 de la plateforme Bing Maps for Enterprise n’échappe pas à la règle et on peut tout à fait ajouter de nouvelles fonctionnalités sur des objets existants ou créer ses propres objets s’intégrant dans la même logique.

L’ensemble des éléments définis sont extensibles et on peut tout à fait définir des méthodes supplémentaires sur des classes standards.

Lorsque l’on souhaite apporter un composant complet, l’API permet de charger dynamiquement des modules. Ces modules sont ainsi des fichiers développés en JavaScript qui seront chargé dynamiquement et dont le cycle de vie sera géré à travers l’utilisation de plusieurs méthodes du contrôle AJAX v7.

 

Conseils

Il est toutefois important de rappeler qu’il faut toujours garder à l’esprit que puisqu’il s’agit d’un service en ligne, ce dernier peut évoluer et par conséquent nos extensions pourront avoir à être adaptées au besoin.

imageAussi, il est important d’être conscient de ce que l’on fait lorsqu’on utilise ces principes d’extensions pour des raisons évidents de stabilité et de support de la part de Microsoft. Il serait en effet délicat d’expliquer que l’on aurait remplacé 30% des méthodes existants par ses propres méthodes tout en continuant de demander un support technique.

 

Exemple d’extension simple

Afin de mettre en pratique un cas simple d’extension de l’API, je vais maintenant m’intéresser au cas des classes standards Polygon et Polyline du contrôle AJAX v7.

  • Calcul du nombre de pointAJAX v7 Bing Maps polygone et nombre de points dans un polygone

Dans le cas d’exemple, nous allons ajouter des fonctionnalités nous permettant de très simplement retourner le nombre de point qui compose la géométrie concernée.

Voici le code d’extension associé :

// Extension
if(typeof(Microsoft) !== 'undefined') {
    if(typeof(Microsoft.Maps) !== 'undefined') {
        Microsoft.Maps.Polygon.prototype.getNumPoints = function() {
            return this.getLocations().length;
        };
    }
}

Et en utilisation :

alert(polygon.getNumPoints());

On remarque que l’extension s’effectue par l’intermédiaire de l’objet prototype, approche tout à fait classique en JavaScript et se retrouve donc être très facilement extensible. Il est également possible d’accéder aux autres méthodes définies au sein de la classe concernée.

  • Calcul du périmètre et de l’aireCalcul de la surface d'un polygone et de la longueur d'une polyligne en JavaScript

Pour ce second cas, nous allons continuer d’étendre la classe Polygone de manière à retourner la longueur du périmètre extérieur du polygone ainsi que le calcul son emprise.

Tout d’abord, nous aurons besoin d’une méthode permettant d’estimer approximativement la distance entre 2 emplacements géographiques définis par une latitude et une longitude.

Voici le code nécessaire :

// Utilities
var Wygwam = {
    Utilities: {
        degToRad: function(value) {
            return value * Math.PI / 180;
        },
        radToDeg: function(value) {
            return value * 180 / Math.PI;
        },
        getHaversineDistance: function(locA, locB) {
            var lat1 = this.degToRad(locA.latitude);
            var lon1 = this.degToRad(locA.longitude);
            var lat2 = this.degToRad(locB.latitude);
            var lon2 = this.degToRad(locB.longitude);

            var dLat = lat2 - lat1;
            var dLon = lon2 - lon1;
            var cordLength = Math.pow(Math.sin(dLat / 2), 2) 
                            + Math.cos(lat1)
                            * Math.cos(lat2) 
                            * Math.pow(Math.sin(dLon / 2), 2);
            var centralAngle = 2 * Math.atan2(
                Math.sqrt(cordLength), 
                Math.sqrt(1 - cordLength));

            // earthRadius = 6371 km;
            earthRadius = 6378137;

            return (earthRadius / 1000) * centralAngle;
        }
    }
}

Voici le code d’extension associé :

// Extension
if (typeof (Microsoft) !== 'undefined') {
    if (typeof (Microsoft.Maps) !== 'undefined') {
        Microsoft.Maps.Polygon.prototype.getNumPoints = function () {
            return this.getLocations().length;
        };
        Microsoft.Maps.Polygon.prototype.getDistance = function () {
            var distance = 0;
            var locs = this.getLocations();
            for (var i = 1; i < locs.length; i++) {
                distance += Wygwam.Utilities.getHaversineDistance(locs[ i ], locs[i - 1]);
            }

            return distance;
        };
        Microsoft.Maps.Polygon.prototype.getArea = function () {
            var area = 0;

            var locs = this.getLocations();
            if (locs.length >= 3) {
                var bounds = Microsoft.Maps.LocationRect.fromLocations(locs);
                var x0 = bounds.getNorthwest().longitude;
                var y0 = bounds.getSoutheast().latitude;

                var j = 0;

                // Aggregate the area of triangle
                for (var i = 0; i < locs.length; i++) {
                    j++;
                    if (j == locs.length) j = 0;

                    // Calculate the area
                    var x1 = Wygwam.Utilities.getHaversineDistance(
                        locs[ i ], new Microsoft.Maps.Location(locs[ i ].latitude, x0));
                    var x2 = Wygwam.Utilities.getHaversineDistance(
                        locs[ j ], new Microsoft.Maps.Location(locs[ j ].latitude, x0));
                    var y1 = Wygwam.Utilities.getHaversineDistance(
                    locs[ i ], new Microsoft.Maps.Location(y0, locs[ i ].longitude));
                    var y2 = Wygwam.Utilities.getHaversineDistance(
                    locs[ j ], new Microsoft.Maps.Location(y0, locs[ j ].longitude));

                    area += (x1 * y2) - (x2 * y1);
                }
            }

            return Math.abs(area / 2);
        };
    }
}

Et en utilisation :

alert("Distance in km=" + polygon.getDistance());
alert("Area in square km=" + polygon.getArea());

L’appel d’autres méthodes de l’API est tout à fait réalisable et simple à mettre en œuvre. Votre code final s’en voit grandement réduit et gagne en lisibilité et donc la maintenabilité générale est renforcée.

  • Binding simple et objet liéBinding simplifié avec Bing Maps ajax v7 en Javascript

Enfin, une autre utilisation beaucoup plus régulière dans nos développements consiste à utiliser un objet qui est directement utilisé pour afficher les infoboxes et l’ensemble des informations liées.

Voici le code d’extension associé :

// Extension
if (typeof (Microsoft) !== 'undefined') {
    if (typeof (Microsoft.Maps) !== 'undefined') {
        Microsoft.Maps.Polygon.prototype.dataObject = null,
        Microsoft.Maps.Polygon.prototype.id = null
    }
}

Et l’utilisation ici dans la méthode associée à l’évènement onclick sur le polygone, ici e est un paramètre de type MouseEventArgs :

function clickPolygon(e) {
    if (e.targetType == 'polygon') {
        alert(e.target.id + ' == ' + e.target.dataObject.title);
    }
}

En utilisation, il devient possible de stocker un objet pouvant par exemple provenir d’un Web Service et dont on souhaiterait conserver l’ensemble des propriétés métiers.

 

Exemple de module d’extension

Les modules dynamiques d’extensions développés ont une utilisation propre à Bing Maps for Enterprise et ils vous permettent de construire des éléments complètement indépendants du développement en cours.Développement d'un module dynamique pour Bing Maps AJAX v7 avec Canvas et HTML5

Ces modules doivent être construit de manière à être complètement abstrait et indépendant de votre implémentation ce qui vous permettra notamment de construire un catalogue de fonctionnalités mutualisé entre plusieurs projets. C’est l’approche à privilégier dans le cas de développement d’un quelconque Framework par dessus le contrôle AJAX v7.

Afin d’illustrer l’utilisation et le développement d’un module d’extension, j’ai choisi de créer un module permettant de créer et surtout ajouter, des punaises à travers un canvas HTML5 de manière à fournir des performances optimales sur les navigateurs modernes.

  • Développement du module :

Le développement d’un module repose sur un pattern simple à respecter qui permet de définir un objet global et des méthodes associés.

imageL’ensemble de la démarche de création d’un module peut être retrouvée ici dans la MSDN : http://msdn.microsoft.com/en-us/library/hh125836.aspx

imageLe code source du module sera disponible à travers le portail de Module Bing Maps et en utilisant ce lien : http://www.boonaert.net/element/bingmaps/modules/CanvasEntityManager.js

Le module réalisé s’inspire fortement de celui réalisé par mon camarade Alastair Aitchison réalisant des cartes de chaleur mais sera étendu de manière à couvrir.

  • Cycle de vie d’un module :

Le module est tout d’abord enregistrer de manière à lui définir un nom et surtout une adresse correspondant au script à charger, pour cela on utilise la méthode statique registerModule() disponible à travers l’espace de nom Microsoft.Maps.

Le module est ensuite chargé ce qui correspond globalement à l’instanciation et l’initialisation de ce composant. Cette action est réalisé via l’appel à la méthode statique loadModule().

A la fin du module, il est important de noter que le module signale au contrôle AJAX v7 qu’il a été chargé de manière à déclencher le callback qui dans notre cas charge des données. Ce comportement est établi à travers l’utilisation de l’évènement moduleLoaded.

  • Utilisation du module dans une application d’exemple :

Dans une page statique HTML, le module est utilisé comme suit :

// Register the module
Microsoft.Maps.registerModule('CanvasEntityManager', './CanvasEntityManager.js');
Microsoft.Maps.loadModule('CanvasEntityManager', { callback: loadElements });

Dès lors, le traitement effectué dans le code de l’évènement de callback qui est déclenché est le suivant :

function loadElements() {
    var manager = new CanvasEntityManager(map);
    manager.drawElements(pins); }

Le code s’en voit très fortement simplifié et le module est complètement réutilisable dans d’autres applications.

  • Résultat en exécution :

Insertion en masse avec utilisation du Canvas HTML5 Bing MAps V7

  • Analyse du résultat dans le DOM du contrôle :

Il est important de noter que les deux techniques diffèrent dans la gestion des éléments au sein du DOM du navigateur.

Voici une vue du DOM dans le navigateur dans le cas d’une utilisation classique :

DOM element Bing Maps v7 ajout d'un grand nombre de punaise

Bing Maps DOM en cas d'ajout en masse de punaise

La vue du DOM dans le navigateur dans le cas de l’utilisation du canvas :

Bing Maps Canvas HTML 5 DOM view - utilisation avec HTML5

Bing Maps Canvas HTML 5 DOM view

  • Comparaison des résultats :

En test, il n’y a aucun photo quant à la rapidité ou la fluidité de l’utilisation du canvas qui ne change pas peu importe le nombre de point. Le contrôle Bing Maps avec 10000 punaises laisse apparaitre un ralentissement tout à fait logique puisque Microsoft recommande de ne pas excéder 500 punaises.

Temps de rendu et traitement JavaScript

Le gain est significatif notamment en ce qui concerne le temps de rendu puisqu’ici nous tirons partie de l’accélération graphique des éléments.

Voici l’analyse des temps de rendu et traitement JavaScript:

image

Ici les premières colonnes de chaque navigateur sont pour 1000 punaises, les secondes sont pour 10000 punaises.

On remarque alors que selon les navigateurs, le changement modifie les temps en bien ou en mal. Je suis par ailleurs assez surpris des résultats et suis très persuadé qu’il est possible d’optimiser soit de manière générale, soit pour chaque navigateur de manière indépendante et dédiée.

Impact mémoire

En mémoire aussi on peut observer une différence notable puisque l’ensemble des éléments n’est pas directement présent dans le DOM.

Voici l’analyse de l’état de la mémoire :

Bing Maps memoire empreinte v7

 

  • Considérations :

Bing Maps HTML5 canvas interet en cartographieL’utilisation de ces technologies HTML5 pour afficher de l’information cartographique offre un spectre très étendu de possibilité de présentation, attention toutefois à limiter votre impact en termes de transport réseau et de mémoire dans la gestion des vos éléments.

Le gain ici n’est pas forcément très visible, mais sur nombre de traitement de type “image”, le gain est considérable et c’est sans doute un des gros avantages de l’utilisation du canvas dans un contexte de traitement client par dessus des cartes interactives.

Il est également important de considérer les navigateurs qui ne proposent pas cette fonctionnalité et par conséquent de gérer les scénarios de fallback pour garantir la compatibilité et l’affichage dans les navigateurs ciblés.

Au delà de ces considérations technique, l’affichage d’un si grand nombre de point est une incohérence en soit sous cette forme, on ne peut pas distinguer ou tirer intérêt de cette présentation dans ces cas précis. Par contre, pour générer des cartes de densité de points, de chaleur ou autre, cela peut tout à fait être une option pertinente.

 

Conclusions

Ces possibilités d’extension sous différentes formes permettent d’enrichir le contrôle AJAX v7 tout en vous garantissant une réutilisation maximale de vos développement.

Dans les faits, les modules et extensions ici développés ne doivent pas présenter de dépendances à votre code d’implémentation, vous permettant ainsi de les utiliser dans de nombreux projets. Veillez à éventuellement les extraire dans des fichiers externes (geo.extensions.js par exemple).

A noter également que, si vous le pouvez, vous avez toujours la possibilité de partager vos modules à travers le projet CodePlex dédié qui représente la galerie des contributions communautaires des développements autour de la plateforme Bing Maps for Enterprise et plus particulièrement ce contrôle AJAX en version 7.bonnes pratiques et conclusions bing maps ajax v7 et html5 et extensions

Cet article nous a permis d’aborder les notions d’extension ainsi qu’une brève introduction à l’utilisation des possibilités d’HTML5 au sein d’une carte issue du contrôle Bing Maps AJAX V7, ce qui nous permettra d’aborder ces éléments davantage dans le détail dans les prochains articles.

Si vous avez des questions concernant ces possibilités d’extension ou sur l’utilisation des fonctionnalités d’HTML5 dans un contexte cartographique, n’hésitez surtout pas à me contacter.