Dev.to WebDev 🛠 Dev 👁 0 📖 4 min read

Carte de la Tunisie avec OpenLayers et les tuiles TMaps

Dès qu'une carte doit faire plus qu'afficher quelques marqueurs (projections, couches WMS, édition de formes, vrai travail SIG), c'est souvent vers OpenLayers qu'on se tourne. Dans cet article, on branche les tuiles rast

Carte de la Tunisie avec OpenLayers et les tuiles TMaps

Dès qu'une carte doit faire plus qu'afficher quelques marqueurs (projections, couches WMS, édition de formes, vrai travail SIG), c'est souvent vers OpenLayers qu'on se tourne. Dans cet article, on branche les tuiles raster de TMaps dans OpenLayers, on évite le piège classique de la projection, et on ajoute une petite fonction que les utilisateurs adorent : une URL qui se souvient de l'endroit où l'on se trouve sur la carte.

La démo en ligne : examples.tmaps.tn/02-raster-openlayers

Ou testez-la directement ici, et copiez-la sur CodePen (bouton Fork) pour modifier le code :

Démo OpenLayers sur Sousse, avec la vue actuelle dans l'URL

Avant de commencer

Il vous faut une clé API créée sur la console TMaps, avec votre domaine (et localhost pour le développement) dans ses Authorized Domains. Les jokers ne sont pas acceptés, donc ajoutez chaque sous-domaine un par un.

1. La couche de tuiles

Les tuiles raster de TMaps suivent le schéma XYZ. La source est donc un simple ol.source.XYZ :

const source = new ol.source.XYZ({
  url: 'https://tiles.tmaps.tn/r-tile/{z}/{x}/{y}?api_key=VOTRE_CLE_API',
  maxZoom: 18,
  attributions: '© <a href="https://www.tmaps.tn">TMaps</a>',
});

Chaque tuile est une image PNG de 256 × 256 pixels, et le zoom va de 0 à 18.

2. La projection, le piège classique

C'est l'erreur qui envoie les marqueurs au milieu de la mer. Par défaut, OpenLayers travaille en Web Mercator (EPSG:3857), alors que les coordonnées GPS sont en longitude et latitude (EPSG:4326). Il faut donc les convertir avec ol.proj.fromLonLat, en faisant attention à l'ordre : la longitude vient en premier.

const map = new ol.Map({
  target: 'map',
  layers: [new ol.layer.Tile({ source })],
  view: new ol.View({
    center: ol.proj.fromLonLat([10.637, 35.828]), // Sousse, en [lng, lat]
    zoom: 14,
    maxZoom: 18,
  }),
});

Sousse affichée avec OpenLayers et les tuiles TMaps

3. Garder la vue dans l'URL

Un jour ou l'autre, quelqu'un voudra envoyer « cet endroit précis » à un collègue. Le plus simple est de garder la vue dans le hash de l'URL, sous la forme #zoom,lat,lng : on le met à jour à chaque déplacement de la carte, et on le relit au chargement de la page.

À la lecture, avec Tunis par défaut :

const [zoom = 12, lat = 36.8002, lng = 10.1815] = location.hash
  .slice(1)
  .split(',')
  .filter(Boolean)
  .map(Number);

À l'écriture, après chaque déplacement. history.replaceState change l'adresse sans ajouter une entrée dans l'historique à chaque glissement, donc le bouton Retour continue de fonctionner normalement :

map.on('moveend', () => {
  const view = map.getView();
  const [lon, la] = ol.proj.toLonLat(view.getCenter());
  history.replaceState(null, '', `#${view.getZoom().toFixed(2)},${la.toFixed(6)},${lon.toFixed(6)}`);
});

Avec ça, un lien comme celui-ci ouvre directement la carte sur Djerba :

https://examples.tmaps.tn/02-raster-openlayers/#11,33.80,10.88

Djerba ouverte depuis un lien partagé

4. L'exemple complet

<!doctype html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Carte de la Tunisie à partager</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
  <style>
    html, body, #map { height: 100%; margin: 0; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const API_KEY = 'VOTRE_CLE_API';

    // Vue initiale lue dans l'URL : #zoom,lat,lng
    const [zoom = 12, lat = 36.8002, lng = 10.1815] = location.hash
      .slice(1).split(',').filter(Boolean).map(Number);

    const source = new ol.source.XYZ({
      url: `https://tiles.tmaps.tn/r-tile/{z}/{x}/{y}?api_key=${API_KEY}`,
      maxZoom: 18,
      attributions: '© <a href="https://www.tmaps.tn">TMaps</a>',
    });
    source.once('tileloaderror', () =>
      console.error('Tuiles TMaps indisponibles : vérifiez votre clé API et ses domaines autorisés.'));

    const map = new ol.Map({
      target: 'map',
      layers: [new ol.layer.Tile({ source })],
      view: new ol.View({ center: ol.proj.fromLonLat([lng, lat]), zoom, maxZoom: 18 }),
    });

    // Partage de la vue actuelle via l'URL
    map.on('moveend', () => {
      const view = map.getView();
      const [lon, la] = ol.proj.toLonLat(view.getCenter());
      history.replaceState(null, '', `#${view.getZoom().toFixed(2)},${la.toFixed(6)},${lon.toFixed(6)}`);
    });
  </script>
</body>
</html>

Quelques conseils

Si la carte reste vide, ouvrez l'onglet Réseau du navigateur. Un 401 signifie que la clé est absente ou révoquée. Un 403 signifie que le domaine de la page n'est pas dans les domaines autorisés de la clé, ou que la requête est partie en HTTP simple.

Les tuiles sont envoyées avec des en-têtes de cache longs : revenir sur la carte est donc très rapide.

Vous utilisez un bundler ? Le même code fonctionne avec import { Map, View } from 'ol', TileLayer depuis ol/layer/Tile, XYZ depuis ol/source/XYZ et fromLonLat depuis ol/proj.

Pour aller plus loin

Dans le prochain article : les tuiles vectorielles avec MapLibre GL, quatre styles, le mode sombre et une vue en 3D.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.