Introduction
Mapbox GL JS est une bibliothèque JavaScript open-source puissante pour afficher des cartes vectorielles interactives et 3D dans les navigateurs web. En 2026, elle reste le choix privilégié pour les applications nécessitant des rendus fluides, des zooms infinis et une personnalisation extrême des styles. Contrairement aux solutions raster traditionnelles comme Leaflet avec tiles images, Mapbox utilise WebGL pour un rendu GPU-accéléré, idéal pour les dashboards géospatiaux, les apps de livraison ou les visualisations immersives.
Ce tutoriel intermediate vous guide de l'initialisation basique à des fonctionnalités avancées comme les couches GeoJSON dynamiques, les événements interactifs et les animations flyTo. Vous obtiendrez des exemples de code complets, prêts à copier-coller, pour une intégration immédiate. À la fin, vous saurez optimiser les performances et éviter les pièges courants. Préparez votre token Mapbox gratuit et plongez dans un setup progressif qui build une carte complète en quelques étapes.
Prérequis
- Un compte Mapbox gratuit pour obtenir un token d'accès public (créez-en un sur account.mapbox.com).
- Connaissances de base en HTML, CSS et JavaScript moderne (ES6+).
- Un éditeur de code comme VS Code et un serveur local (Live Server ou
npx serve). - Navigateur récent avec support WebGL (Chrome, Firefox).
Initialisation de la carte de base
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox GL JS Basique</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // Remplacez par VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [2.3522, 48.8566], // Paris
zoom: 10
});
</script>
</body>
</html>Ce fichier HTML autonome initialise une carte centrée sur Paris avec le style 'streets-v12'. Le token Mapbox est obligatoire pour les requêtes API ; remplacez-le par le vôtre. Le conteneur #map occupe toute la viewport pour un rendu immersif. Ouvrez ce fichier dans un navigateur pour voir la carte interactive de base.
Ajout des contrôles de navigation
Les contrôles natifs de Mapbox améliorent l'UX en ajoutant zoom, rotation et position GPS. Ils sont ajoutés après l'événement load de la carte pour éviter les erreurs de timing. Imaginez-les comme des boutons de cockpit : intuitifs et essentiels pour la navigation.
Intégration des contrôles NavigationControl et Geolocation
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox avec Contrôles</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [2.3522, 48.8566],
zoom: 10
});
map.on('load', () => {
map.addControl(new mapboxgl.NavigationControl({ showCompass: true }));
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: { enableHighAccuracy: true },
trackUserLocation: true
}));
});
</script>
</body>
</html>Après le chargement (map.on('load')), on ajoute NavigationControl pour zoom/rotation et GeolocateControl pour la géolocalisation. showCompass: true active la boussole. Cela évite les ajouts prématurés qui crashent si la carte n'est pas prête. Testez en cliquant sur le bouton GPS.
Ajout de marqueurs et couches GeoJSON
Pour des données personnalisées, utilisez des marqueurs Popup ou des sources GeoJSON. Les couches vectorielles sont rendues côté client pour une scalabilité infinie, comme superposer des données dynamiques sur une base satellite.
Ajout d'un marqueur avec popup et couche GeoJSON
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox Marqueurs et GeoJSON</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [2.3522, 48.8566],
zoom: 10
});
map.on('load', () => {
// Marqueur avec popup
const marker = new mapboxgl.Marker({ color: 'red' })
.setLngLat([2.3522, 48.8566])
.setPopup(new mapboxgl.Popup().setHTML('<h3>Tour Eiffel</h3><p>📍 Icône de Paris</p>'))
.addTo(map);
// Couche GeoJSON exemple (parcs à Paris)
map.addSource('parcs', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: { type: 'Polygon', coordinates: [[[2.29, 48.86], [2.30, 48.86], [2.30, 48.85], [2.29, 48.85], [2.29, 48.86]]] },
properties: { nom: 'Parc exemple' }
}]
}
});
map.addLayer({
id: 'parcs-fill',
type: 'fill',
source: 'parcs',
paint: { 'fill-color': 'green', 'fill-opacity': 0.5 }
});
});
</script>
</body>
</html>Un marqueur rouge avec popup s'affiche à Paris ; cliquez pour voir le contenu HTML. La source GeoJSON ajoute une couche polygonale verte pour un parc fictif, scalable à des milliers de features via fetch(). Les layers se superposent sans latence grâce au rendu vectoriel.
Gestion des événements interactifs
Capturez les clics, mouvements ou zooms pour des interactions dynamiques, comme des infobulles contextuelles ou des filtres de données. C'est le cœur des apps réactives.
Événements click et flyTo animation
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox Événements Interactifs</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
button { position: absolute; top: 10px; left: 10px; z-index: 1; }
</style>
</head>
<body>
<div id="map"></div>
<button onclick="flyToLyon()">Voler vers Lyon</button>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [2.3522, 48.8566],
zoom: 10
});
map.on('load', () => {
map.on('click', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(`<p>Clic à ${e.lngLat.lat.toFixed(4)}, ${e.lngLat.lng.toFixed(4)}</p>`)
.addTo(map);
});
});
function flyToLyon() {
map.flyTo({
center: [4.8357, 45.7640],
zoom: 12,
essential: true,
duration: 3000
});
}
</script>
</body>
</html>L'événement click ajoute une popup aux coordonnées cliquées. Le bouton déclenche flyTo pour une animation fluide vers Lyon (3s). essential: true priorise l'animation GPU. Cela rend la carte vivante et réactive aux inputs utilisateur.
Personnalisation 3D et styles avancés
Activez le terrain 3D ou des styles custom pour des visualisations immersives. Les expressions Mapbox permettent des rendus data-driven dynamiques.
Activation du mode 3D avec terrain et extrusion
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox 3D et Terrain</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/satellite-streets-v12',
center: [2.3522, 48.8566],
zoom: 12,
pitch: 45,
bearing: -17.6
});
map.on('style.load', () => {
map.setTerrain({ source: 'mapbox-dem', exaggeration: 1.5 });
map.addLayer({
id: 'buildings-3d',
type: 'fill-extrusion',
source: 'composite',
source-layer: 'building',
paint: {
'fill-extrusion-color': '#aaa',
'fill-extrusion-height': ['interpolate', ['linear'], ['zoom'], 15, 0, 15.05, ['get', 'height']],
'fill-extrusion-base': 0,
'fill-extrusion-opacity': 0.6
}
});
});
</script>
</body>
</html>Style satellite avec pitch et bearing pour vue oblique. setTerrain active le relief 3D via DEM ; fill-extrusion extrude les bâtiments basés sur leur hauteur. Utilisez style.load pour ajouter des layers post-chargement. Parfait pour visualisations urbaines immersives.
Optimisation avec clusters GeoJSON
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mapbox Clusters Optimisés</title>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.11.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidXNlcn9ub20iLCJhIjoiY29kZV90b2tlbiJ9'; // VOTRE_TOKEN
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [2.3522, 48.8566],
zoom: 10
});
map.on('load', () => {
map.addSource('points', {
type: 'geojson',
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
data: {
type: 'FeatureCollection',
features: Array.from({length: 100}, (_, i) => ({
type: 'Feature',
geometry: { type: 'Point', coordinates: [2.35 + Math.random()*0.02, 48.85 + Math.random()*0.02] },
properties: { point_count: 1 }
}))
}
});
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'points',
filter: ['has', 'point_count'],
paint: {
'circle-color': ['step', ['get', 'point_count'], '#51bbd6', 100, '#f1f075', 750, '#f28cb1'],
'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40]
}
});
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'points',
filter: ['has', 'point_count'],
layout: { 'text-field': '{point_count_abbreviated}' }
});
map.on('click', 'clusters', (e) => {
const features = map.queryRenderedFeatures(e.point, { layers: ['clusters'] });
map.getSource('points').getClusterExpansionZoom(features[0].properties.cluster_id, (zoom) => {
map.easeTo({ center: features[0].geometry.coordinates, zoom });
});
});
});
</script>
</body>
</html>Génère 100 points aléatoires autour de Paris avec clustering automatique (cluster: true). Les cercles changent de taille/couleur par densité ; cliquez pour expander. Idéal pour des datasets massifs (millions de points) sans perte de perf, grâce au clustering vectoriel.
Bonnes pratiques
- Toujours utiliser
map.on('load')oustyle.loadpour les ajouts post-init, évitant les erreurs de source manquante. - Cachez le token en prod : utilisez des variables d'environnement ou un proxy backend pour les apps publiques.
- Limitez les layers à 50 max ; fusionnez-les pour les perfs GPU.
- Testez WebGL avec
map.isStyleLoaded()et fallback vers raster si needed. - Optez pour styles custom via Mapbox Studio pour data-driven styling.
Erreurs courantes à éviter
- Token invalide ou absent : Erreur 401/403 ; vérifiez public vs secret et quotas (gratuit : 50k users/mois).
- Ajout de layers avant
load: Rien ne s'affiche ; wrappez dans l'événement. - Oubli de
filtersur layers : Clusters ou popups foireux ; utilisez['==', 'type', 'Feature']. - Mémoire leak sur événements :
off()avanton()pour éviter doublons sur re-renders React/Vue.
Pour aller plus loin
Explorez la documentation officielle Mapbox GL JS pour les maps offline ou GLTF 3D. Intégrez avec React via react-map-gl. Pour maîtriser la cartographie pro, découvrez nos formations Learni sur JavaScript avancé et geospatial.