Aller plus loin avec Leaflet : 10 outils à intégrer

Géolocalisation, recherche d'adresse, mesure, dessin, clusters, carte de chaleur, glisser-déposer, légende, plein écran : le code prêt à copier.

Votre carte Leaflet affiche un fond et des données. Voici dix outils à lui ajouter pour en faire une vraie application : chacun est autonome, avec le code complet à copier dans votre app.js (on suppose que la variable map existe déjà). Les plugins sont chargés depuis un CDN, en version figée.

1. Ma position (géolocalisation)

Intégré à Leaflet, aucun plugin nécessaire. Le navigateur demande l'autorisation, et la page doit être servie en https (ou localhost).

let maPosition = null;
function localiser() { map.locate({ setView: true, maxZoom: 17, enableHighAccuracy: true }); }

map.on('locationfound', (e) => {
  if (maPosition) map.removeLayer(maPosition);
  maPosition = L.layerGroup([
    L.circle(e.latlng, { radius: e.accuracy, weight: 1, fillOpacity: 0.1 }),   // précision
    L.circleMarker(e.latlng, { radius: 7, color: '#fff', weight: 3, fillColor: '#1e88e5', fillOpacity: 1 })
  ]).addTo(map);
});
map.on('locationerror', () => alert('Position indisponible ou refusée'));

2. Recherche d'adresse (API Adresse)

La Base Adresse Nationale est interrogeable gratuitement, sans clé, via l'API Adresse de l'État. Un champ de recherche dans un contrôle Leaflet :

const Recherche = L.Control.extend({
  onAdd() {
    const box = L.DomUtil.create('div', 'leaflet-bar');
    box.innerHTML = '<input type="search" placeholder="Rechercher une adresse…" style="width:240px;padding:6px 8px;border:0">';
    L.DomEvent.disableClickPropagation(box);
    const input = box.querySelector('input');
    input.addEventListener('keydown', async (e) => {
      if (e.key !== 'Enter' || !input.value.trim()) return;
      const url = 'https://api-adresse.data.gouv.fr/search/?limit=1&q=' + encodeURIComponent(input.value);
      const res = await (await fetch(url)).json();
      if (!res.features.length) return alert('Adresse introuvable');
      const [lon, lat] = res.features[0].geometry.coordinates;   // GeoJSON : [lon, lat]
      map.setView([lat, lon], 18);
      L.marker([lat, lon]).addTo(map).bindPopup(res.features[0].properties.label).openPopup();
    });
    return box;
  }
});
new Recherche({ position: 'topleft' }).addTo(map);

Pour une liste de suggestions pendant la frappe, appelez la même URL avec autocomplete=1&limit=5 à chaque saisie (en attendant ~250 ms entre deux requêtes).

3. Coordonnées sous la souris

const Coords = L.Control.extend({
  onAdd() { this._div = L.DomUtil.create('div', 'coords'); return this._div; }
});
const coords = new Coords({ position: 'bottomleft' }).addTo(map);
map.on('mousemove', (e) => {
  coords._div.textContent = `${e.latlng.lat.toFixed(5)}, ${e.latlng.lng.toFixed(5)}`;
});
.coords { background: rgba(255,255,255,.85); padding: 2px 8px; border-radius: 6px; font: 12px monospace; }

4. Mesurer une distance

Leaflet sait calculer la distance entre deux points (map.distance, en mètres). On cumule les segments d'une ligne tracée au clic ; double-clic pour recommencer.

map.doubleClickZoom.disable();
let points = [];
const trace = L.polyline([], { color: '#8b6cff', dashArray: '6 6' }).addTo(map);

map.on('click', (e) => {
  points.push(e.latlng);
  trace.setLatLngs(points);
  let total = 0;
  for (let i = 1; i < points.length; i++) total += map.distance(points[i - 1], points[i]);
  trace.bindTooltip(total < 1000 ? `${total.toFixed(1)} m` : `${(total / 1000).toFixed(3)} km`, { permanent: true }).openTooltip(e.latlng);
});
map.on('dblclick', () => { points = []; trace.setLatLngs([]); trace.unbindTooltip(); });

Pour les surfaces, ajoutez Turf.js et utilisez turf.area(polygone) (résultat en m²). L'outil Mesure distance & surface de CartoForge fait les deux.

5. Dessiner et exporter (Leaflet-Geoman)

Barre d'outils complète pour dessiner, modifier, déplacer et supprimer des points, lignes et polygones.

<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@2.17.0/dist/leaflet-geoman.css">
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@2.17.0/dist/leaflet-geoman.js"></script>
map.pm.setLang('fr');
map.pm.addControls({ position: 'topleft', drawCircle: false, drawCircleMarker: false, drawText: false });

// Export de tout ce qui a été dessiné, en GeoJSON
function exporter() {
  const geojson = map.pm.getGeomanLayers(true).toGeoJSON();
  const a = document.createElement('a');
  a.href = URL.createObjectURL(new Blob([JSON.stringify(geojson)], { type: 'application/geo+json' }));
  a.download = 'dessin.geojson';
  a.click();
}

6. Regrouper les marqueurs (Leaflet.markercluster)

Au-delà de quelques centaines de marqueurs, la carte devient illisible et lente. Les clusters les regroupent par proximité et affichent leur nombre.

<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5.3/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.5.3/dist/leaflet.markercluster.js"></script>
fetch('arbres.geojson').then((r) => r.json()).then((data) => {
  const clusters = L.markerClusterGroup({ showCoverageOnHover: false, maxClusterRadius: 50 });
  clusters.addLayer(L.geoJSON(data, {
    onEachFeature: (f, layer) => layer.bindPopup(f.properties.espece || 'Arbre')
  }));
  map.addLayer(clusters);
});

7. Carte de chaleur (Leaflet.heat)

<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
fetch('accidents.geojson').then((r) => r.json()).then((data) => {
  // [latitude, longitude, intensité]
  const pts = data.features.map((f) => [f.geometry.coordinates[1], f.geometry.coordinates[0], 1]);
  L.heatLayer(pts, { radius: 22, blur: 18, maxZoom: 15 }).addTo(map);
});

8. Ouvrir un fichier par glisser-déposer

L'utilisateur dépose un GeoJSON sur la carte : il s'affiche et la carte se cadre dessus. Rien n'est envoyé sur un serveur.

const zone = map.getContainer();
zone.addEventListener('dragover', (e) => e.preventDefault());
zone.addEventListener('drop', async (e) => {
  e.preventDefault();
  for (const file of e.dataTransfer.files) {
    const data = JSON.parse(await file.text());
    const couche = L.geoJSON(data, {
      onEachFeature: (f, layer) => layer.bindPopup(
        Object.entries(f.properties || {}).map(([k, v]) => `<b>${k}</b> : ${v}`).join('<br>'))
    }).addTo(map);
    map.fitBounds(couche.getBounds());
  }
});

Pour lire aussi Shapefile, GeoPackage, KML ou DXF, la visionneuse SIG montre la marche à suivre (bibliothèques JSZip, sql.js, dxf-parser).

9. Légende

const Legende = L.Control.extend({
  onAdd() {
    const div = L.DomUtil.create('div', 'legende');
    const classes = [['Maison', '#e0553d'], ['Garage', '#3d8bfd'], ['Jardin', '#2fb673']];
    div.innerHTML = '<strong>Nature</strong>' + classes.map(([nom, c]) =>
      `<div><i style="background:${c}"></i> ${nom}</div>`).join('');
    return div;
  }
});
new Legende({ position: 'bottomright' }).addTo(map);
.legende { background: #fff; padding: 8px 12px; border-radius: 10px; font: 13px sans-serif; line-height: 1.6; }
.legende i { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }

10. Plein écran

L'API Fullscreen des navigateurs suffit, inutile d'ajouter un plugin :

const PleinEcran = L.Control.extend({
  onAdd() {
    const a = L.DomUtil.create('a', 'leaflet-bar');
    a.href = '#'; a.title = 'Plein écran'; a.textContent = '⛶';
    a.style.cssText = 'display:grid;place-items:center;width:34px;height:34px;background:#fff;font-size:18px';
    L.DomEvent.on(a, 'click', (e) => {
      L.DomEvent.preventDefault(e);
      document.fullscreenElement ? document.exitFullscreen() : map.getContainer().requestFullscreen();
    });
    return a;
  }
});
new PleinEcran({ position: 'topleft' }).addTo(map);
document.addEventListener('fullscreenchange', () => map.invalidateSize());   // recalcule la taille

Et ensuite ?

Démonstration : les 10 outils réunis

Tous les outils de ce tutoriel sur une même carte (les 600 arbres sont fictifs) :

  • ◎ ma position · recherche en haut à droite (tapez une adresse puis Entrée) · coordonnées en bas à gauche ;
  • 📏 mesure : clics successifs, double-clic pour recommencer ;
  • barre Geoman (à gauche) pour dessiner, puis 💾 pour télécharger le dessin en GeoJSON ;
  • clusters d'arbres (cliquez pour zoomer) et carte de chaleur à cocher en bas à droite, avec la légende ;
  • déposez un fichier .geojson sur la carte, et ⛶ pour le plein écran.