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
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 :
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,
}),
});
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
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
- TMaps, une alternative à Google Maps pour la Tunisie : www.tmaps.tn
- Toutes les démos en ligne : examples.tmaps.tn
- Le code source, sous licence MIT : github.com/tmaps-tn/tmaps-snippets
- La collection Postman : postman.com/tmaps-tn/tmaps-api
- La documentation des tuiles raster : tmaps.tn/documentation
Dans le prochain article : les tuiles vectorielles avec MapLibre GL, quatre styles, le mode sombre et une vue en 3D.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.

