Construire une carte de zones de livraison

Une zone de livraison n'est pas un cercle. Un cercle tracé à cinq kilomètres traverse la rivière, la gare de triage et l'escarpement comme s'ils n'existaient pas, et il promet une livraison à une adresse que votre chauffeur met quarante minutes à atteindre. Ce que vous voulez, c'est l'ensemble des lieux accessibles en un temps donné par de vraies routes : une isochrone.

Ce guide construit trois zones autour d'un dépôt, les dessine, et y teste l'adresse d'un client. Le code est du TypeScript ordinaire. Pour le câblage React, Next.js, Vue ou Nuxt, partez des recettes par framework et collez-y ces appels.

Trouver le dépôt et dessiner les zones

Partez d'une adresse plutôt que de coordonnées relevées à la main : le même code fonctionne encore quand le dépôt déménage. Un seul appel d'isochrone renvoie ensuite les trois bandes sous forme de FeatureCollection GeoJSON, de la plus large à la plus étroite.

const [depot] = await unmap.geocoder.search("1010 8 St SW, Calgary", { limit: 1 });
if (!depot) throw new Error("depot address not found");
 
const zones = await unmap.router.isochrone([depot.lng, depot.lat], {
  minutes: [10, 20, 30],
  mode: "auto",
});

La longitude d'abord, partout. Si vos zones apparaissent dans l'océan Indien, c'est pour cela.

Quatre contours est le plafond et 120 minutes la durée la plus longue. Les deux reprennent les limites de service de Valhalla appliquées par la passerelle : en demander plus donne un 400 qui nomme la règle plutôt qu'une troncature silencieuse. Chaque contour est une passe de calcul distincte dans le conteneur d'itinéraires, et c'est la raison même du plafond.

Pour un coursier à vélo, passez mode: "bicycle", et pour une camionnette soumise à des limites de hauteur ou de poids, mode: "truck" avec un profil de véhicule. La documentation des itinéraires liste les cinq modes.

Les afficher sur la carte

La réponse a déjà la forme attendue par MapLibre : elle devient donc une source telle quelle. Le remplissage d'abord et le contour ensuite gardent les frontières lisibles là où les bandes se chevauchent.

import type { FeatureCollection } from "@unmap/routing";
 
function drawZones(zones: FeatureCollection) {
  unmap.map!.on("load", () => {
    unmap.map!.addSource("zones", { type: "geojson", data: zones });
    unmap.map!.addLayer({
      id: "zones-fill",
      type: "fill",
      source: "zones",
      paint: { "fill-color": "#FF3E9A", "fill-opacity": 0.15 },
    });
    unmap.map!.addLayer({
      id: "zones-line",
      type: "line",
      source: "zones",
      paint: { "line-color": "#FF3E9A", "line-width": 1 },
    });
  });
}

Tester une adresse dans une zone

Aucun point de terminaison ne répond à « cette adresse est-elle dans ma zone de livraison », et il ne devrait pas y en avoir : la réponse dépend de vos règles d'affaires, pas du réseau routier. Géocodez l'adresse, puis demandez à la carte dans quelle bande le point tombe.

async function bandFor(address: string): Promise<number | undefined> {
  const [customer] = await unmap.geocoder.search(address, { limit: 1 });
  if (!customer) return undefined;
 
  const pixel = unmap.map!.project([customer.lng, customer.lat]);
  const [hit] = unmap.map!.queryRenderedFeatures(pixel, { layers: ["zones-fill"] });
  return hit?.properties?.contour as number | undefined;
}

contour est la valeur en minutes de la bande : la fonction renvoie donc la tranche de temps de trajet plutôt qu'un simple oui ou non. Elle lit la carte rendue, ce qui veut dire qu'elle ne répond que pour les zones actuellement dessinées, et seulement dans le navigateur. Pour le même test sur un serveur, conservez la FeatureCollection et faites-y une vérification point-dans-polygone avec une bibliothèque de géométrie.

Ce que ces zones sont et ne sont pas

Une isochrone est un modèle du réseau routier, pas une promesse sur un mardi après-midi. Elle ne sait rien de votre quai de chargement, de la pause du chauffeur, de la zone scolaire à 15 h ni de la circulation en temps réel, car le graphe d'itinéraires ne contient aucune donnée de trafic en direct. Traitez les bandes comme la forme de votre zone de service et gardez la promesse faite au client comme une décision d'affaires par-dessus.

La couverture s'arrête à la frontière. Un dépôt près de Windsor obtient une zone qui s'arrête net à la rivière au lieu d'atteindre Détroit, parce que le graphe d'itinéraires est l'extrait du Canada.

Pour aller plus loin