Cartographie et géocodage : Leaflet au service de l’administration

Cet article fait partie d’une série consacrée aux back-offices Angular de Rezo Pouce. Après avoir présenté les deux applications et leur architecture commune, l’architecture de l’espace d’administration, l’authentification et le contrôle d’accès, la gestion des territoires et le pilotage du service Rezo Séniors, ce dernier volet aborde la couche transversale qui irrigue l’ensemble du back-office : la cartographie.

Le besoin

Les articles précédents ont mentionné les cartes à plusieurs reprises — la carte d’une commune sur la fiche territoire, le marqueur repositionnable d’un point d’arrêt, la carte d’itinéraire lors de la création d’un trajet Séniors. Chaque fois, la carte était au service d’un module fonctionnel. Mais derrière ces usages variés se cache une seule couche technique, partagée par l’ensemble du back-office.

Le défi n’était pas d’afficher une carte — Leaflet fait cela très bien. Le défi était de construire un ensemble de composants et de services suffisamment souples pour répondre à des besoins très différents : visualiser les limites géographiques d’un territoire, placer des centaines de marqueurs sur une carte, permettre un géocodage bidirectionnel entre un formulaire et un marqueur, calculer un itinéraire entre deux adresses, ou encore capturer une carte en image pour l’insérer dans un PDF. Tout cela avec une expérience fluide pour des utilisateurs qui ne sont pas des techniciens.

Plusieurs cartes, un seul socle

Le back-office utilise la cartographie dans cinq contextes distincts.

La carte du territoire affiche les contours géographiques en superposition GeoJSON. Elle distingue deux cas : un territoire administratif (département, région) montre les empreintes de tous ses territoires enfants, tandis qu’un territoire technique montre sa propre empreinte — les limites de l’intercommunalité ou de l’agglomération. Les fichiers GeoJSON sont générés en amont via un processus QGIS à partir des données officielles des communes de France, puis servis par l’API.

La carte d’une commune combine les contours géographiques, récupérés via l’API geo.api.gouv.fr, avec les marqueurs des points d’arrêt et des points d’inscription. Un code couleur distingue les types de points. Le mode plein écran permet de travailler confortablement sur des communes étendues.

La carte d’un point d’arrêt est la plus interactive. Le marqueur est repositionnable par glisser-déposer, et chaque déplacement déclenche un géocodage inverse pour mettre à jour l’adresse postale. Inversement, modifier l’adresse dans le formulaire recalcule les coordonnées et repositionne le marqueur. Cette synchronisation bidirectionnelle, orchestrée par des Observables RxJS, élimine les incohérences entre la position sur la carte et l’adresse enregistrée.

La carte d’itinéraire apparaît dans le module Séniors, lors de la création ou de la consultation d’un trajet. Elle affiche le tracé entre le point de départ et la destination, avec la distance et la durée estimées. Le tracé est calculé côté serveur par un moteur de routage dédié.

La carte de capture est un cas à part. Ce n’est pas une carte destinée à être vue à l’écran, mais à être photographiée — transformée en image pour illustrer les fiches mobilité PDF. Le composant de capture utilise dom-to-image pour convertir le rendu Leaflet en image téléchargeable, directement depuis l’interface du configurateur de fiches.

Les couches de tuiles

Toutes ces cartes partagent un système de couches de tuiles configurable. Quatre fonds de carte sont disponibles : Teritorio (la couche par défaut, sobre et lisible), OpenStreetMap (la référence généraliste), ESRI Aerial (l’imagerie aérienne, utile pour repérer un point d’arrêt dans son environnement physique) et une couche topographique. L’utilisateur bascule de l’une à l’autre selon son besoin — un gestionnaire qui configure un point d’arrêt en zone rurale appréciera la vue aérienne pour vérifier qu’il se situe bien au bon carrefour.

La gestion des couches est centralisée dans un service Angular dédié, qui gère aussi les couches GeoJSON superposées — contours de territoire, contours de commune. Chaque composant carte consomme ce service sans avoir à connaître les détails des tuiles ou des sources géographiques.

Géocodage multi-sources

Le géocodage — la transformation d’une adresse en coordonnées, et inversement — est omniprésent dans le back-office. Il intervient quand un gestionnaire crée un point d’arrêt, quand un référent Séniors saisit une adresse de départ, quand le système importe des points depuis un fichier CSV.

Le problème est qu’aucun service de géocodage n’est fiable à 100 %. Google Maps est le plus précis, mais il est payant et soumis à des quotas. La Base Adresse Nationale (BAN), interrogée via Addok, est gratuite et excellente sur le territoire français, mais ne couvre pas les adresses étrangères. Nominatim et Pelias, basés sur OpenStreetMap, offrent une couverture mondiale mais avec une précision variable.

La solution retenue est un service de géocodage abstrait avec stratégie de fallback, implémenté côté API. Le front n’interroge jamais directement les fournisseurs de géocodage — il passe par les endpoints de l’API, qui orchestre les appels aux différentes sources. Chaque requête est d’abord envoyée à la source principale. En cas d’échec ou de résultat insuffisant, les sources secondaires prennent le relais, dans un ordre configurable. Un convertisseur par fournisseur normalise les réponses vers un format unifié — label, numéro, rue, localité, code postal, code commune, coordonnées — de sorte que ni le front, ni le reste de l’application ne savent quel service a effectivement répondu.

L’architecture de l’API suit une logique hexagonale : un port de géocodage, plusieurs adaptateurs (BAN, Google, Pelias, Mobicoop), et un service de domaine qui orchestre les appels et les fallbacks. Côté front, un service Angular consomme ces endpoints et expose les résultats aux composants — autocomplétion, géocodage direct, géocodage inverse — sans avoir connaissance de la mécanique multi-sources qui opère derrière.

L’autocomplétion d’adresse

La saisie d’une adresse dans le back-office passe par un composant d’autocomplétion qui interroge les services de géocodage en temps réel. À chaque frappe, une requête est envoyée au fournisseur principal, et les suggestions s’affichent dans un menu déroulant.

Deux variantes coexistent. L’autocomplétion libre permet de saisir n’importe quelle adresse — c’est le mode utilisé pour les trajets Séniors, où le départ et la destination peuvent être n’importe où. L’autocomplétion contrainte valide l’adresse saisie contre les communes présentes en base — c’est le mode utilisé pour la création de points d’arrêt, où un point doit obligatoirement se situer dans une commune rattachée au territoire.

Le calcul d’itinéraire

Le calcul d’itinéraire est sollicité dans le module Séniors pour estimer la distance et la durée d’un trajet entre deux adresses. Le front transmet les coordonnées de départ et d’arrivée à l’API, qui interroge un moteur de routage. Nous utilisions initialement le service GraphHopper, mais celui-ci étant devenu payant, nous avons basculé vers une instance auto-hébergée par Mobicoop qui implémente la même solution — même moteur, même qualité de routage, sans dépendance à un service tiers payant.

L’API retourne la distance en kilomètres, la durée en secondes et la géométrie du tracé, que le front dessine sur la carte Leaflet. Ces données servent aussi au calcul automatique de l’indemnité conducteur — distance multipliée par le prix au kilomètre configuré par territoire.

Le clustering

Certains territoires comptent plusieurs centaines de points d’arrêt. Afficher tous les marqueurs simultanément rend la carte illisible et dégrade les performances. Le back-office utilise Leaflet.markercluster pour regrouper automatiquement les marqueurs proches en cercles numérotés. Au fur et à mesure que l’utilisateur zoome, les clusters se décomposent en marqueurs individuels.

Ce mécanisme est transparent pour le gestionnaire — il voit une carte lisible à n’importe quel niveau de zoom, et peut toujours cliquer sur un cluster pour zoomer sur la zone concernée.

Les marqueurs

Les marqueurs ne sont pas de simples punaises sur la carte. Chaque type d’entité a son propre marqueur — forme, couleur, icône — grâce à Leaflet Extra Markers. Un point d’arrêt actif, un point d’arrêt inactif, un point d’inscription, un point retour : chacun est immédiatement identifiable visuellement.

Les marqueurs sont gérés par un service dédié qui construit les icônes, positionne les marqueurs sur la carte, et attache les popups d’information — ces bulles qui s’affichent au clic et résument les données essentielles de l’entité (nom, adresse, statut).

La capture de carte pour les fiches mobilité

Les fiches mobilité sont des documents PDF générés pour chaque commune, destinés à être imprimés. Elles nécessitent une illustration cartographique — la carte des points d’arrêt de la commune. Mais un PDF ne peut pas embarquer une carte interactive. Il faut une image.

Le composant de capture résout ce problème sans sortir du navigateur. Il rend une carte Leaflet avec les marqueurs positionnés, puis utilise dom-to-image pour convertir le conteneur DOM en image PNG. Le gestionnaire cadre la zone souhaitée, déclenche la capture, et l’image est uploadée comme document associé à la commune. Le configurateur de fiches mobilité l’intègre ensuite automatiquement dans le PDF.

Ce qui aurait pu être un processus fastidieux — ouvrir un logiciel de cartographie, exporter une image, l’importer dans un outil de mise en page — se fait en trois clics dans le navigateur.

Ce que ce module illustre

La cartographie du back-office Rezo Pouce n’est pas un module au sens classique — c’est une couche de services et de composants qui traverse l’ensemble de l’application. C’est ce qui rend sa conception intéressante. Un composant carte unique, paramétrable par ses entrées (marqueurs, couches, zoom, interactivité), sert des usages aussi différents que la visualisation d’un territoire et la capture d’image pour un PDF.

Le géocodage multi-sources illustre un principe récurrent dans ce projet : ne pas dépendre d’un seul fournisseur. La même logique de fallback qui sécurise le géocodage se retrouve dans d’autres parties de l’écosystème. C’est un réflexe d’architecte qui vient de la réalité du terrain — quand un service tiers tombe ou change ses conditions, le système continue de fonctionner.

Enfin, la synchronisation bidirectionnelle carte-formulaire est un bon exemple de la valeur ajoutée d’un framework réactif comme Angular couplé à RxJS. Ce qui aurait été un enchaînement fragile de callbacks devient un flux de données lisible et testable. Le marqueur bouge, l’adresse se met à jour. L’adresse change, le marqueur se repositionne. L’utilisateur n’a pas besoin de comprendre le mécanisme — il constate simplement que tout reste cohérent.

Cela dit, Angular n’embarque pas de système de store intégré, contrairement à d’autres frameworks comme Vue avec Pinia. La gestion de l’état repose sur des services injectables exposant des Subject et BehaviorSubject RxJS. C’est puissant, mais sans la structure imposée par un store — actions typées, état centralisé, mutations traçables — la cohérence de l’ensemble repose entièrement sur la rigueur du développeur. Qui émet, qui souscrit, quand désouscrire, comment éviter les effets de bord entre composants : autant de questions auxquelles le framework ne répond pas à votre place. Sur un module comme la cartographie, où plusieurs composants réagissent aux mêmes flux de données, cette discipline n’est pas optionnelle.

Une question ou un projet ?

Je suis disponible pour en discuter.

Me contacter