Skip to content
Learni
View all tutorials
JavaScript

Comment intégrer Mapbox GL JS pour cartes interactives en 2026

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

index.html
<!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

index-controls.html
<!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

index-markers-geojson.html
<!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

index-events.html
<!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

index-3d.html
<!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

index-clusters.html
<!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') ou style.load pour 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 filter sur layers : Clusters ou popups foireux ; utilisez ['==', 'type', 'Feature'].
  • Mémoire leak sur événements : off() avant on() 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.