Construire un localisateur de succursale la plus proche
« La plus proche » a deux sens, et ils divergent assez souvent pour que cela compte. La succursale la plus proche à vol d'oiseau peut se trouver de l'autre côté d'une rivière dont le pont est huit kilomètres en amont. Ce guide trouve des candidates par distance, classe ensuite la liste courte par temps de trajet réel, et trace l'itinéraire vers la gagnante.
Le code est du TypeScript ordinaire. Pour le câblage React, Next.js, Vue ou Nuxt, partez des recettes par framework.
Trouver le client, puis les candidates
nearby trie par distance réelle depuis un point d'ancrage et porte une distance en mètres sur
chaque résultat. Prenez plus de candidates qu'il n'en faut : la liste courte est précisément ce que
vous allez classer correctement.
const [customer] = await unmap.geocoder.search("Bow Valley Square, Calgary", { limit: 1 });
if (!customer) throw new Error("customer address not found");
const candidates = await unmap.geocoder.nearby("shop.convenience", {
near: [customer.lng, customer.lat],
radius: 5000,
limit: 5,
});radius est en mètres, vaut 5000 par défaut et est borné entre 50 et 50000. Si vous comparez vos
propres succursales plutôt qu'une catégorie du corpus, sautez cet appel et utilisez votre liste :
c'est l'étape de classement ci-dessous qui compte.
Classer la liste courte par temps de trajet
Une requête d'itinéraire par candidate, en parallèle, puis la plus courte durée. Cinq candidates font cinq appels facturés, ce qui est le coût honnête de l'écart entre distance à vol d'oiseau et distance réelle.
import type { GeocodeResult } from "@unmap/geocoding";
async function nearestByDriveTime(from: [number, number], candidates: GeocodeResult[]) {
const legs = await Promise.all(
candidates.map(async (candidate) => ({
candidate,
route: await unmap.router.route(from, [candidate.lng, candidate.lat], { mode: "auto" }),
})),
);
return legs.sort((a, b) => a.route.durationSeconds - b.route.durationSeconds)[0];
}Gardez la liste courte. C'est le seul endroit où un localisateur devient coûteux, et calculer un itinéraire vers toutes vos succursales plutôt que vers les cinq plus proches est la façon dont une page finit par faire quarante appels pour répondre à une seule question.
Tracer le chemin
geometry est une LineString GeoJSON : elle devient une source sans aucune traduction.
import type { RouteResult } from "@unmap/routing";
function drawRoute(route: RouteResult) {
unmap.map!.addSource("leg", {
type: "geojson",
data: { type: "Feature", properties: {}, geometry: route.geometry },
});
unmap.map!.addLayer({
id: "leg-line",
type: "line",
source: "leg",
layout: { "line-cap": "round", "line-join": "round" },
paint: { "line-color": "#FF3E9A", "line-width": 3 },
});
}durationSeconds et distanceMeters reviennent sur le même résultat : l'étiquette à côté de la
succursale (« 12 min, 6,4 km ») ne demande donc pas un second appel.
Là où cela donne la mauvaise réponse
Si nearby ne trouve aucune candidate dans le rayon, le bon comportement est d'élargir une fois
puis de le dire au client, et non d'élargir jusqu'à ce que quelque chose corresponde. Une
succursale à 40 km est une réponse vraie à la mauvaise question.
La catégorie doit exister dans le corpus. shop.convenience est un identifiant de catégorie de la
documentation du géocodage ; un mot qui n'en est pas un ne renvoie rien
plutôt que de deviner.
Et la couverture s'arrête à la frontière : un client à Windsor ne sera pas associé à une succursale de Détroit, même quand c'est vraiment la plus proche.
Pour aller plus loin
- Trouver des lieux à proximité pour la version la plus simple
- Obtenir un itinéraire pour l'appel d'itinéraire seul
- API de géocodage pour la liste des catégories et les quatre points de terminaison