Accueil / Blog / Métier / 2013 / Infrastructure webmapping minimaliste (partie 3) - Leaflet

Infrastructure webmapping minimaliste (partie 3) - Leaflet

Par Simon Georges — publié 18/12/2013, édité le 23/02/2016
Continuant notre série d'article sur l'application webmapping du CAUE24, nous présentons le code Leaflet produit.
Infrastructure webmapping minimaliste (partie 3) - Leaflet

Note : l'intégralité du code présenté dans cet article est consultable sur le dépot Github du projet ou directement sur le site.

Afficher une carte

Afficher une carte avec Leaflet est très simple, l'API étant vraiment facile à utiliser. Avant d'indiquer les 2 lignes à utiliser, nous devons préciser que comme nous restons sur la même page web, tout en changeant "virtuellement" de page, nous devons régulièrement réinitialiser notre carte. Cela nous permet également de factoriser une partie de code de création de carte :

// Variables globales.
var CaueViews = {}; // Contiendra nos fonctions.
var map; // Contiendra notre carte.

CaueViews.initMap = function(category) {
  // Supprime l'éventuelle instance existante.
  if (map instanceof L.Map) {
    map.remove();
  }
  // Initialise la nouvelle instance
  map = L.map('map');
  // Ajoute les réglages communs à toutes nos cartes, comme la gestion de l'échelle.
  L.control.scale({imperial: false}).addTo(map);
}

Grâce à l'utilisation de la variable globale "map", nous pouvons y accéder de tout notre scope et réaliser parfois des traitements complexes impossibles autrement. Maintenant que nous disposons d'une fonction réutilisable, pour afficher une carte en utilisant l'API Leaflet, nous n'avons besoin que des quelques lignes suivantes :

CaueViews.displayHomePage = function() {
  // On initialise la carte.
  CaueViews.initMap();
  // On la centre.
  map.setView([45.10, 1.57], 9);
  // On ajoute le fond de carte.
  var caueUrl = 'http://{s}.livembtiles.makina-corpus.net/caue24/CAUE/{z}/{x}/{y}.png';
  var caueAttrib = 'Données cartographiques fournies par le CAUE24';
  L.tileLayer(caueUrl, {minZoom: 8, maxZoom: 11, attribution: caueAttrib, subDomains: 'abcdefgh'}).addTo(map);
}

Les lignes précédentes suffisent à afficher notre fond de carte, le reste du code sera explicité ensuite. Le fond de carte est servi par notre serveur "livembtiles.makina-corpus.net", qui dispose des 8 sous-domaines a.livembtiles, b.livembtiles, etc. pour permettre le requêtage simultané de plus de tuiles, et ainsi améliorer les performances.

Changer de fond de carte selon le zoom

Une des demandes du client était de changer la couche de fond de la carte à certains niveaux de zoom, pour utiliser le fond orthophoto disponible. En utilisant le plugin Leaflet MultiTileLayer, cela se fait très facilement : il suffit de remplacer la ligne "L.TileLayer" citée précédemment par :

  L.TileLayer.multi({
    14: {
      url: caueUrl,
      subdomains: 'abcdefgh'
    },
    15: {
      url: 'http://{s}.livembtiles.makina-corpus.net/caue24/orthophoto24/{z}/{x}/{y}.png',
      subdomains: 'abcdefgh'
    }
  }, {
    minZoom: 10,
    maxZoom: 15,
    attribution: caueAttrib
  }).addTo(map);

Cette syntaxe signifie : jusqu'au niveau de zoom 14, sert le fond CAUE classique, à partir du 15, utilise l'orthophoto. Nous pensions initialement directement utiliser le WMS du fond orthophoto, mais le plugin MultiTileLayer ne fonctionne pas avec une couche WMS, nous avons donc simplement converti cette couche en MBTiles pour la servir avec notre propre serveur de tuiles.

Chargement des couches de données

Chargement dynamique des GeoJSONs

Nous n'avons aucune connaissance à l'avance du nombre de couches de données dynamiques que le client souhaite ajouter sur l'écran. Nous avons donc du fixer une nomenclature pour les fichiers : "data/geojson/[territoire]_[categorie]_[nombre].geosjson", "nombre" étant un simple compteur entier. Voici le code qui charge dynamiquement les fichiers :

CaueViews.addGeoJSONs = function(community, category) {
  // Initialisation du sélecteur de couches.
  var layers = L.control.layers(null, null, {collapsed: false});
  function loadUrl(baseUrl, n) {
    // Charge dynamiquement les GeoJSONs
    $.ajax({
      url: baseUrl + "_" + n + ".geojson",
      dataType: 'json',
    }).done(function(data) {
      if (n == 1) {
        // Au moins 1 geojson => On ajoute le sélecteur de couches à la carte.
        layers.addTo(map);
      }
      // On ajoute le GeoJSON (cette fonction sera explicitée au prochain paragraphe).
      // Le nom addGeoJSONLegend ne se contente pas d'ajouter la légende, mais ajoute
      // Egalement la couche de GEOJSON complète (cela mériterait une réécriture).
      CaueViews.addGeoJSONLegend(layers, community, category, data, n);
      // On essaie de charger le suivant.
      loadUrl(baseUrl, n + 1);
    }).fail(function(jqXHR, textStatus, errorThrown) {
      // Rien à faire en cas d'erreur, à part stocker la boucle.
    });
  }
  // Chargement des GeoJSON
  var url = "data/geojson/" + community + "_" + category;
  loadUrl(url, 1);
};

En fait, une simple boucle récursive qui charge les GeoJSON, si ils existent, par une requête ajax.

Contrôle du rendu par le client

En plus de choisir le nombre de couches dynamiques chargées, le client souhaitait partiellement contrôler le rendu des couches. Pour cela, nous avons ajouté aux données géographiques quelques propriétés dans le GeoJSON, sur lequel le client peut agir pour choisir : la couleur de la couche, le nom et la description associée pour le composant de légende de la carte, si la couche est active par défaut au chargement, et si elle permet de déclencher des évènements (popups) lors du clic. C'est finalement assez simple :

CaueViews.addGeoJSONLegend = function(layers, community, category, data, n) {
  // Nom de la couche (pour la légende).
  var name = data.name || 'Sans nom';
  // Description de la couche (pour la légende).
  var description = data.description || '';
  // Couleur de la couche
// On récupère éventuellement la couleur du style courant en cas d'absence. var color = data.color || CaueViews.getColorFromFeature(category, n); // Statut initial de la couche. var active = data.active || "false"; // La couche est-elle interactive ? var interactive = data.interactive || "true"; // Texte d'information de la couche (utilisation future) var displayText = data.displayText; // On initialise le style de la couche. var style = { "color": color, "weight": 1, "fillOpacity": 0.4, "opacity": 0.8, }; // On prépare l'interactivité. onEachFeature = function (feature, layer) { if (interactive != "false") { layer.on('click', function(e) { // Cette fonction sera décrite au paragraphe suivant. CaueViews.clickLayer(e.target, community, category); }); } } // Nous créons la couche. // Le pointToLayer, non décrit ici, remplace les marqueurs standards Leaflet par des marqueurs SVG, stylables. var geojsonLayer = L.geoJson(data, {pointToLayer: CaueViews.pointToLayer, onEachFeature: onEachFeature, style: style}); // Nous l'ajoutons à la carte si elle est active par défaut. if (active == "true") { geojsonLayer.addTo(map); } // Dans tous les cas, nous l'ajoutons au sélecteur. layers.addOverlay(geojsonLayer, name); // Et enfin, au composant légende (avec balisage "Bootstrap" pour le tooltip)). // L'initialisation de cette légende n'est pas commentée dans cet article, // reportez-vous au code correspondant sur le dépôt. $('.info.legend').append('[HTML Markup]'); // Et actionnons les tooltips sur la légende. $('.info.legend div').tooltip({container:'body'}); }

Il s'avère que notre système "manuel" est similaire à celui de MapBox qui pourrait devenir une norme pour ce type de besoin : https://github.com/mapbox/simplestyle-spec. A garder en tête pour le prochain projet.

Conclusion

Grâce à l'utilisation de Leaflet disposant d'une API très simple, il est possible de réaliser des applications de webmapping à forte valeur ajoutée fonctionnelle en réduisant le code Javascript nécessaire à sa plus simple expression (vous constatez dans cet article que chaque fonctionnalité nécessite moins d'une dizaine de lignes de code).

Si cette technologie vous intéresse, venez suivre notre formation Leaflet.

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Optimisation de la production de tuiles vectorielles de fond de carte OpenStreetMap pour un service à la demande : Makina Maps Optimisation de la production de tuiles vectorielles de fond de carte OpenStreetMap pour un service à la demande : Makina Maps 04/02/2020

Frédéric Rodrigo, expert OpenStreetMap, présente Makina Maps, une solution permettant de servir ...

Une Cagnotte reversée à la fondation OpenStreetMap a été organisée par Makina Corpus lors du Paris Open Source Summit ! Une Cagnotte reversée à la fondation OpenStreetMap a été organisée par Makina Corpus lors du Paris Open Source Summit ! 28/01/2020

Les 10 et 11 décembre derniers, Makina Corpus était présente à la 5ème édition du Paris Open ...

Mise en pratique de RxJS dans Angular Mise en pratique de RxJS dans Angular 13/08/2018

Les quelques bases suffisantes pour bien utiliser RxJS dans Angular. Cet article a été écrit ...

Créer une carte avec Umap Créer une carte avec Umap 03/07/2019

[ Tuto ] créer une carte utilisant OpenStreetMap et y ajouter ou importer des données, puis ...

Retour sur le State of the Map France 2019 Retour sur le State of the Map France 2019 26/06/2019

Makina Corpus était une nouvelle fois sponsor de la conférence annuelle d'OpenStreetMap France et ...