Leaflet est une bibliothèque JavaScript open source créée en 2010 par Vladimir Agafonkin, un développeur ukrainien. Elle permet de créer facilement des cartes interactives pour le web. C’ets une des plus connues et des plus ancienne.
Toute la documention est ici : https://leafletjs.com/reference.html
Pour fonctionner, il faut du HTML, du CSS et bien évidemment du JS.
Voici un exemple minimal :
<!-- Import de la bibliothèque et du css-->
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<div id="map"></div> // Création de la carte dans le div #map
const map = L.map('map') // L designe la bibliothèque leaflet. La fonction map crée une carte vide
// Position et zoom
map.setView([51.505, -0.09], 13);
// Ajout d'une couche de tuiles raster
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
})
// On ajoute la couche à la carte
tiles.addTo(map);#map {
height: 500px;
}- Couches de tuiles raster
Dans Leaflet, le fond de carte est généralement fourni par des tuiles raster, c’est-à-dire de petites images carrées qui s’assemblent comme un puzzle pour recouvrir toute la surface de la carte aux différents niveaux de zoom. Ces tuiles proviennent de serveurs externes. Certains fournisseurs, comme OpenStreetMap, Carto ou Stamen, proposent des fonds libres d’accès (souvent avec attribution obligatoire), tandis que d’autres, comme Esri, Mapbox ou Google Maps, nécessitent une clé d’API et peuvent être soumis à des quotas ou des restrictions d’usage. Pour changer de fond de carte dans Leaflet, il suffit de remplacer l’URL des tuiles par celle du fournisseur souhaité, ou bien d’ajouter un menu permettant à l’utilisateur de choisir entre plusieurs options.
Par exemple, essayez ceci :
const tiles = L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_toner_background/{z}/{x}/{y}{r}.{ext}', {
minZoom: 0,
maxZoom: 20,
attribution: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
ext: 'png'
});Essayez d’autres fonds de carte en vous appuyant sur cette page : leaflet-providers/preview
- Ajouter une épingle (marker)
L.marker([51.5, -0.09]).addTo(map)- Ajouter une popup
L.marker([51.5, -0.09]).addTo(map)
.bindPopup('Une jolie popup.<br> facilement personnalisable.') // popup en html
.openPopup(); // Ouvre la popup- Ajouter plusieurs markeurs
Pour ajouter plusieurs épingles, il suffit de stocker les données dans un tableau d’objets.
const points = [
{ lat: 51.5, lng: -0.09, name: "Marker 1" },
{ lat: 51.51, lng: -0.1, name: "Marker 2" },
{ lat: 51.49, lng: -0.08, name: "Marker 3" }
];Puis, de faire une boucle pour parcourir chaque élément.
points.forEach(p => {
L.marker([p.lat, p.lng]) // keys lat et lng dans le tableau de données
.addTo(map)
});Et si on veut ajouter les popups, ils suffet d’ajouter ceci :
points.forEach(p => {
L.marker([p.lat, p.lng])
.addTo(map)
.bindPopup(p.name); // popup avec le nom
});- Regrouper les markers
le clustering n’est pas inclus dans Leaflet par défaut. Il faut charger le plugin Leaflet.markercluster en modifiant la partie html. Attention, l’ordre est important.
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<div id="map"></div>Puis
// Carte
const map = L.map('map').setView([51.505, -0.09], 13);
// Tuiles
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
// Tableau de points
const points = [
{ lat: 51.5, lng: -0.09, name: "Marker 1" },
{ lat: 51.51, lng: -0.1, name: "Marker 2" },
{ lat: 51.49, lng: -0.08, name: "Marker 3" },
{ lat: 51.52, lng: -0.12, name: "Marker 4" },
{ lat: 51.53, lng: -0.13, name: "Marker 5" }
];
// Création d’un groupe de clusters
const markers = L.markerClusterGroup();
// Ajout des marqueurs au cluster
points.forEach(p => {
const marker = L.marker([p.lat, p.lng]).bindPopup(p.name);
markers.addLayer(marker);
});
// Ajout du cluster à la carte
map.addLayer(markers);- Personnaliser les markeurs
Dans Leaflet, il existe plusieurs moyens de changer le style des épingles
- Changer l’image de l’épingle avec
L.icon
Voir https://leafletjs.com/examples/custom-icons/
const myIcon = L.icon({
iconUrl: 'https://cdn-icons-png.flaticon.com/512/684/684908.png', // image du marker
iconSize: [32, 32], // taille de l’icône [largeur, hauteur]
iconAnchor: [16, 32], // point de l’icône qui correspond à la position sur la carte
popupAnchor: [0, -32] // point d’attache du popup par rapport à l’icône
});
// Ajout du marker avec icône personnalisée
L.marker([51.5, -0.09], { icon: myIcon })
.addTo(map)
.bindPopup("Marker personnalisé !");- Utiliser un dessin SVG
const svgIcon = L.divIcon({
html: `<svg width="24" height="24">
<circle cx="12" cy="12" r="10" fill="purple" />
</svg>`,
className: '', // supprime le style par défaut
iconSize: [24, 24]
});
L.marker([51.5, -0.09], { icon: svgIcon }).addTo(map);- Les contrôles
Dans Leaflet, presque tous les éléments de contrôle de la carte sont regroupés sous le concept de contrôles (L.Control). Il en existe plusieurs types :
- Zoom (L.control.zoom)
On peut supprimer ou déplacer le bouton de zoom
const map = L.map('map', { zoomControl: false }).setView([51.505, -0.09], 13);
L.control.zoom({ position: 'bottomright' }).addTo(map);- Échelle (L.control.scale)
On peut ajouter une barre d’échelle
L.control.scale().addTo(map);- Panneau de couches (L.control.layers)
Sur une carte leaflet, il est courant d’avoir un panneau pour contrôler les différentes couches
// Création de la carte
const map = L.map('map').setView([51.505, -0.09], 13);
// Fonds de carte
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
});
const watercolor = L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.{ext}', {
minZoom: 1,
maxZoom: 16,
attribution: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
ext: 'jpg'
});
// Par défaut, ajouter OSM
osm.addTo(map);
// Tableau de points
const points = [
{ lat: 51.5, lng: -0.09, name: "Marker 1" },
{ lat: 51.51, lng: -0.1, name: "Marker 2" },
{ lat: 51.49, lng: -0.08, name: "Marker 3" },
{ lat: 51.52, lng: -0.12, name: "Marker 4" },
{ lat: 51.53, lng: -0.13, name: "Marker 5" }
];
// Création d'un groupe de marqueurs (couche)
const markersLayer = L.layerGroup();
points.forEach(p => {
L.marker([p.lat, p.lng])
.bindPopup(p.name)
.addTo(markersLayer);
});
// Ajouter la couche de marqueurs à la carte
markersLayer.addTo(map);
// Définition des fonds de carte et des couches superposables
const baseMaps = {
"OpenStreetMap": osm,
"Stamen watercolor": watercolor
};
const overlayMaps = {
"Markers": markersLayer
};
// Ajouter le contrôle des couches (menu en haut à droite)
L.control.layers(baseMaps, overlayMaps, { collapsed: false }).addTo(map);- Evénements
Dans leaflet, on peut ajouter des evenements sur tous les élements. Ici par exemple, un clic sur la carte.
map.on('click', function(e) {
alert("Clic à " + e.latlng.toString());
});- Polylignes, polygones, etc.
On peut dessiner des lignes et des polygones
const line = L.polyline([
[51.5, -0.09],
[51.51, -0.1],
[51.52, -0.12]
], { color: 'red' }).addTo(map);
const polygon = L.polygon([
[51.5, -0.09],
[51.52, -0.1],
[51.48, -0.06]
], {
color: 'blue', // bordure
fillColor: 'lightblue', // intérieur
fillOpacity: 0.5
}).addTo(map);- Couches geoJSON
La fonction L.geoJSON permet d’ajouter à leaflet n’importe quel geoJSON. Cela permet d’ajouter n’importe quel fond de carte. Voici un exemple.
// Création de la carte
const map = L.map('map').setView([51.505, -0.09], 13);
// Fond de carte
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
// Données GeoJSON avec deux polygones
const geojsonPolygons = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "name": "Zone 1" },
"geometry": {
"type": "Polygon",
"coordinates": [[
[-0.1, 51.5],
[-0.12, 51.52],
[-0.08, 51.52],
[-0.1, 51.5]
]]
}
},
{
"type": "Feature",
"properties": { "name": "Zone 2" },
"geometry": {
"type": "Polygon",
"coordinates": [[
[-0.09, 51.48],
[-0.11, 51.49],
[-0.07, 51.49],
[-0.09, 51.48]
]]
}
}
]
};
// Ajouter les polygones à la carte
L.geoJSON(geojsonPolygons, {
style: function(feature) {
return {
color: 'green',
fillColor: 'lightgreen',
fillOpacity: 0.4
};
},
onEachFeature: function(feature, layer) {
if (feature.properties && feature.properties.name) {
layer.bindPopup(feature.properties.name);
}
}
}).addTo(map);Bien sur, dans la pratique, on n’écrit pas le geoJSON directement dans le code. Mais on l’importe. Nous verrons cela un petit peu plus tard.
- Légende
On peut ajouter une légende comme cela
<!-- Import de la bibliothèque et du css-->
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<div id="map"></div>// Création de la carte dans le div #map
const map = L.map("map"); // L designe la bibliothèque leaflet. La fonction map crée une carte vide
// Position et zoom
map.setView([51.505, -0.09], 13);
// Ajout d'une couche de tuiles raster
const tiles = L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{
attribution: "© OpenStreetMap",
},
);
const legend = L.control({ position: "bottomright" });
legend.onAdd = function (map) {
const div = L.DomUtil.create("div", "legend");
div.innerHTML = `
<h4>Légende</h4>
<i style="background: red"></i> Zone A<br>
<i style="background: blue"></i> Zone B<br>
`;
return div;
};
legend.addTo(map);
// On ajoute la couche à la carte
tiles.addTo(map);#map {
height: 500px;
}
.legend {
background: white;
padding: 10px;
border-radius: 6px;
line-height: 1.4;
box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
}
.legend i {
display: inline-block;
width: 14px;
height: 14px;
margin-right: 6px;
}On peut ajouter n’importe quel contenu dans la légende. Par exemple du SVG
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<div id="map"></div>// --- Initialisation de la carte ---
const map = L.map("map").setView([48.8566, 2.3522], 12);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19
}).addTo(map);
// --- Légende SVG ---
const legend = L.control({ position: "bottomright" });
legend.onAdd = function (map) {
const div = L.DomUtil.create("div", "legend");
div.innerHTML = `
<h4>Légende</h4>
<svg width="170" height="100">
<!-- Rond rouge -->
<g transform="translate(0,0)">
<circle cx="10" cy="10" r="8" fill="#e41a1c"></circle>
<text x="28" y="14" font-size="12">Catégorie A</text>
</g>
<!-- Carré bleu -->
<g transform="translate(0,28)">
<rect x="2" y="2" width="16" height="16" fill="#377eb8"></rect>
<text x="28" y="15" font-size="12">Catégorie B</text>
</g>
<!-- Ligne verte -->
<g transform="translate(0,58)">
<line x1="2" y1="9" x2="18" y2="9"
stroke="#4daf4a" stroke-width="4"></line>
<text x="28" y="12" font-size="12">Trajet</text>
</g>
</svg>
`;
return div;
};
legend.addTo(map);
#map {
width: 100%;
height: 400px;
}
.legend {
background: white;
padding: 10px 12px;
border-radius: 6px;
line-height: 1.4;
box-shadow: 0 0 6px rgba(0,0,0,0.25);
font-family: sans-serif;
}
.legend h4 {
margin: 0 0 6px;
font-size: 14px;
text-align: left;
}Vous pouvez aussi utiliser d’autres bibliothèques pour dessiner la légende. Par exemple, la bibliothèque geoviz que nous verrons une petit peu plus tar et qui dispose des fonctions pour dessiner des légendes complexes en svg. Nous verrons cela plus tard. Mais d’ici là, voici un exemple.
<!-- Import de la bibliothèque et du css-->
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script
src="https://cdn.jsdelivr.net/npm/geoviz@0.9.4"
charset="utf-8"
></script>
<div id="map"></div>// Création de la carte
const map = L.map("map").setView([51.505, -0.09], 13);
// Ajout des tuiles
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© OpenStreetMap",
}).addTo(map);
// --- LÉGENDE GEOVIZ ---
const legend = L.control({ position: "bottomright" });
legend.onAdd = function () {
// Conteneur Leaflet
const div = L.DomUtil.create("div", "legend");
// Appel geoviz → renvoie un objet SVGSVGElement
const svgElem = geoviz.legend.typo_vertical({
title: "Legend",
subtitle: "(With geoviz)",
frame: true,
});
// Insérer le SVG (car c'est un objet DOM)
div.appendChild(svgElem);
return div;
};
legend.addTo(map);#map {
height: 500px;
}- Minimap
Le plugin MiniMap permet d’ajouer une carte de localisation.
On le charge en ajoutant ces lignes dans le HTML
<link rel="stylesheet" href="https://unpkg.com/leaflet-minimap/dist/Control.MiniMap.min.css" />
<script src="https://unpkg.com/leaflet-minimap/dist/Control.MiniMap.min.js"></script>Puis :
// Création de la carte principale
const map = L.map('map').setView([51.505, -0.09], 13);
// Fond de carte principal
const osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
// Ajouter un marker pour tester
L.marker([51.5, -0.09]).addTo(map).bindPopup("Marker principal");
// Création d’un fond pour la MiniMap (souvent une version plus simple)
const miniLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
// Ajouter la MiniMap
const miniMap = new L.Control.MiniMap(miniLayer, {
toggleDisplay: true, // bouton pour ouvrir/fermer
minimized: false, // démarrer affiché ou réduit
position: 'bottomright'
}).addTo(map);- Measure
On charge le plugin leaflet-measure en ajoutant fans le HTML
<link rel="stylesheet" href="https://unpkg.com/leaflet-measure/dist/leaflet-measure.css" />
<script src="https://unpkg.com/leaflet-measure/dist/leaflet-measure.js"></script>Puis
// Ajouter la carte
const map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
L.marker([51.5, -0.09]).addTo(map).bindPopup("Marker principal");
// Contrôle de mesure
const measureControl = L.control.measure({
primaryLengthUnit: 'meters',
secondaryLengthUnit: 'kilometers',
primaryAreaUnit: 'sqmeters',
secondaryAreaUnit: 'hectares',
activeColor: '#db4a29',
completedColor: '#9b2d14',
position: 'topright'
}).addTo(map);
// Forcer le clic sur la carte à ne pas scroll
map.getContainer().addEventListener('mousedown', e => e.preventDefault());
map.getContainer().addEventListener('touchstart', e => e.preventDefault());Quelles alternatives ?
La bibliothèque maplibre-gl
MapLibre est une bibliothèque JavaScript open source permettant d’afficher des cartes interactives vectorielles sur le web, en 2D ou en 3D (vue “globe”). Elle est née en 2020 suite à la décision de Mapbox de fermer le code source de Mapbox GL JS à partir de la version 2. MapLibre constitue donc une alternative libre, soutenue par une communauté active.
<!-- Import de la bibliothèque et du css-->
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css" rel="stylesheet" />
<div id="map"></div>Comme pour leaflet, on a besoin du css
#map {
height: 500px;
}Puis, on crée une carte
const map = new maplibregl.Map({
container: 'map',
style: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',
center: [2.5, 46.8], // [lon, lat]
zoom: 6,
});Vue globe
const map = new maplibregl.Map({
container: 'map',
style: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',
center: [2.5, 46.8], // [lon, lat]
zoom: 6
});
map.on('style.load', () => {
map.setProjection({
type: 'globe', // Set projection to globe
});
});Ajout d’un marker
const marker = new maplibregl.Marker()
.setLngLat([12.550343, 55.665957])
.addTo(map);Voir la documentation et les exemples ici