Aller au contenu
Langue
DE EN FR
Démarrer un projet

cloudtec Stack : Coordinate Picker en open source

Chercher des coordonnées dans une carte externe, les copier et les coller à l’aveugle dans le système cible : nous avons remplacé ce détour par notre propre widget basé sur OpenLayers.

Une fonctionnalité qui semble modeste, mais qui contient un bon nombre de détails : notre Coordinate Picker, basé sur la bibliothèque open source OpenLayers. Il est intégré directement dans nos plateformes, pour que personne ne doive quitter l’application lors de la saisie d’un lieu.

Pourquoi nous avons développé le Coordinate Picker

Beaucoup de nos projets comportent une carte : sites d’entreprise, rendez-vous par site, randonnées, activités. Pour qu’un point apparaisse sur cette carte, ses coordonnées doivent être saisies, et c’est précisément là que commençait le détour. Chercher le lieu dans un service de cartographie, copier les coordonnées, les coller dans le formulaire. Ensuite, le système cible ne montrait plus si le point était vraiment juste. De plus, il fallait expliquer d’où viennent les valeurs et dans quel ordre les saisir, pour ne pas intervertir longitude et latitude.

C’est une rupture inutile dans l’utilisation. Plutôt que de continuer à expliquer, nous avons développé notre propre widget de sélection des coordonnées, placé directement dans le formulaire de nos plateformes.

Champ de formulaire « Coordonnées du point de départ » avec une carte swisstopo intégrée, des boutons de zoom à gauche et un bouton de suppression en haut à droite.
Placer un point : choisir la section de carte, cliquer dans la carte : le marqueur est posé, les coordonnées figurent dans le champ.

Ce qu’est OpenLayers

OpenLayers est une bibliothèque JavaScript open source pour les cartes interactives dans les applications web. Ce qui la rend utile pour nous :

  • Open source. Libre d’utilisation, de modification et de redistribution, tant que les conditions de licence sont respectées.
  • Cartes interactives. Plusieurs couches, des marqueurs, des popups ainsi que le zoom et le déplacement font partie de la bibliothèque.
  • Libre choix du fond de carte. OpenStreetMap, les cartes swisstopo de la Confédération et d’autres sources WMS, WMTS ou XYZ peuvent être intégrées, ainsi que des couches propres.
  • Formats de géodonnées. Les données vectorielles comme GeoJSON et KML s’affichent directement, les données raster s’ajoutent via WMS ou WMTS.
  • Extensible. Des fonctions propres, un style propre et des interactions adaptées sont prévus d’emblée, et non ajoutés après coup.
  • Utilisable sur mobile. Les cartes fonctionnent sur différentes tailles d’écran et avec une commande tactile.
  • Documentation et communauté. De nombreux exemples et une communauté de développement active, comme souvent dans l’open source.

Comment le Coordinate Picker est réalisé

Vue de l’extérieur, la fonction est simple : un widget avec une carte dans laquelle vous pouvez zoomer et placer un point. Le point est enregistré et peut être réaffiché à n’importe quel autre endroit de l’application. Derrière, il y a un peu plus.

La même carte avec un marqueur déjà placé et le bouton de suppression en haut à droite.
Un point placé peut être déplacé ou entièrement supprimé avec le bouton en haut à droite.

Principes de base

Comme fond de carte, nous utilisons la carte pixélisée de swisstopo. Cela limite le Coordinate Picker à la Suisse. Pour nos projets, c’est le bon périmètre ; pour d’autres régions, il suffit de changer la source cartographique. Le widget propose trois interactions : zoomer, réinitialiser et supprimer. En arrière-plan se trouvent deux champs de saisie pour la longitude et la latitude, remplis dès que le point est placé.

La fonctionnalité est réalisée en JavaScript standard avec jQuery. Des paramètres globaux définissent le niveau de zoom et la section de carte à l’ouverture. Une bounding box limite la carte au territoire suisse, de sorte qu’aucun point ne puisse être placé en dehors du fond de carte ; elle conserve en même temps les proportions lorsque la taille du widget change.

S’y ajoutent des event listeners, par exemple sur le clic qui place le repère. L’événement d’OpenLayers est alors traduit en un événement propre au Coordinate Picker, auquel d’autres actions peuvent se rattacher, par exemple l’enregistrement direct du point. À l’ouverture, des mécanismes garantissent que le widget ne s’initialise pas deux fois et que les actions ne s’exécutent pas deux fois. Les données déjà présentes sont chargées et les boutons s’affichent en conséquence.

Deux systèmes de coordonnées

En arrière-plan, deux projections fonctionnent côte à côte. La carte de swisstopo fournit EPSG:3857, soit WGS 84 / Pseudo-Mercator, la grille Web Mercator habituelle pour les cartes en tuiles. Vers l’extérieur, le widget travaille en revanche avec EPSG:4326 : WGS 84 en longitude et latitude, tel que le fournissent aussi les appareils GPS et tel que nous enregistrons les valeurs. Une conversion entre les deux est nécessaire ; OpenLayers fournit la fonction pour cela. Si la projection est mal configurée, les points tombent à côté, et la recherche d’erreurs devient laborieuse, car le widget fonctionne normalement par ailleurs.

Code

Pour les curieuses et curieux, et dans l’esprit de l’open source : les paramètres par défaut et la conversion, qui permettent de comprendre le principe.

class CoordinatePicker extends EventTarget {
    // global defaults
    static options = {
        center: [915000, 5910000], // center of switzerland
        boundingBox: [670433, 5744676, 1162476, 6078756], // swiss extent in EPSG:3857
        zoom: 14, // used when there is already a coordinate set
        backgroundLayerUrl: 'https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg',
    };

    // expects coordinates in GPS (WGS84, EPSG:4326) format
    setData(long, lat) {
        // set data on input fields
        let inputs = this.getInputs();
        inputs.long.val(long);
        inputs.lat.val(lat);
        inputs.long.trigger("change");
        inputs.lat.trigger("change");

        // convert to map coordinates and set the marker
        let coords = ol.proj.transform([long, lat], 'EPSG:4326', 'EPSG:3857');
        this.markerSource.clear();
        this.markerSource.addFeature(new ol.Feature({
            geometry: new ol.geom.Point(coords)
        }));
    }
}
Rédigé par Lukas Knöpfel Senior Fullstack Software Developer

Tech 4 minutes de lecture