Makina Blog

Le blog Makina-corpus

Infrastructure web mapping minimaliste (partie 3) - Leaflet


Continuant notre série d'article sur l'application web mapping du CAUE24, nous présentons le code Leaflet produit.

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 web mapping à 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.

Formations associées

Formations SIG / Cartographie

Formation Leaflet

À distance (FOAD) Du 1er au 2 juillet 2024

Voir la formation

Formations Front end

Formation Angular

Nantes Du 22 au 24 mai 2024

Voir la formation

Formations SIG / Cartographie

Formation QGIS

Nantes Du 2 au 4 avril 2024

Voir la formation

Actualités en lien

18/12/2013

Infrastructure web mapping minimaliste (partie 4) - Javascript

Dans ce dernier article sur l'application web mapping du CAUE24, nous traitons de quelques autres points Javascript ne concernant pas directement Leaflet.

Voir l'article
Image
sig-tilemill
11/12/2013

Infrastructure web mapping minimaliste (partie 2) - TileMill

Dans le cadre de notre architecture web mapping minimaliste, nous présentons quelques astuces pour styler une carte avec TileMill.

Voir l'article
Image
 infrastructure-SIG-leaflet
02/12/2013

Infrastructure web mapping minimaliste (partie 1)

Cette série d'articles présente par l'intermédiaire d'une réalisation une architecture de web mapping minimaliste, basée sur Leaflet et Jekyll.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus