Aller au contenu

Recherche et itinéraires

Le géocodeur et le panneau d'itinéraire reposent sur vos propres primitives shadcn et appellent l'API de géocodage et l'API d'itinéraires. Chaque appel qu'ils font compte pour une requête, facturée comme les autres. well-search et legal-land-search sont le géocodeur avec d'autres libellés, dans Composants de superposition.

npx shadcn@latest registry add @unmap=https://registry.unmap.dev/r/{name}.json
npx shadcn@latest add @unmap/geocoder

La ligne React enregistre le registre une fois par projet, ce qui permet ensuite de nommer les éléments @unmap/<item> ; shadcn-vue n'a pas de registry add et prend directement l'URL de l'élément. Les fichiers arrivent dans components/ui/ à côté des vôtres ; rien n'est remplacé sans confirmation.

Parcourir tous les éléments sur registry.unmap.dev
ÉlémentRôle
geocoderUne boîte de recherche avec autocomplétion différée qui déplace la carte vers le lieu choisi. Les coordonnées saisies passent par le géocodage inverse ; bbox, proximity et votre propre mise en page des résultats sont facultatifs.
routing-panelDes champs départ/arrivée qui résolvent les deux adresses, demandent un itinéraire et le tracent sur la carte.

Options du géocodeur

Le géocodeur fait un géocodage inverse des coordonnées qu'on y saisit et liste les adresses les plus proches du point. Il lit lat, lng par défaut : 51.05, -114.07 désigne Calgary. Un premier nombre négatif suivi d'un second positif signifie lng, lat : -114.07, 51.05 désigne donc aussi Calgary, car partout au Canada la latitude est positive et la longitude négative. La virgule décimale française fonctionne quand une espace ou un ; sépare les deux nombres, comme dans 51,05 -114,07, alors qu'un 51,05 seul reste une recherche de texte. Le signe moins Unicode compte comme -. Les degrés, minutes et secondes restent une recherche de texte. Un point hors du Canada le dit, en français ou en anglais selon lang. Chaque recherche inverse est une requête, comme une recherche. reverseGeocode={false} cherche plutôt les coordonnées comme du texte. well-search et legal-land-search partent sans géocodage inverse, car des coordonnées saisies dans une boîte UWI ou LSD ne demandent pas une adresse ; passez reverseGeocode (Vue : :reverse-geocode="true") pour le réactiver.

  • bbox ([ouest, sud, est, nord]) garde les résultats dans un rectangle. Le géocodeur filtre dans le navigateur, car l'autocomplétion n'a pas de rectangle côté serveur : il demande plus de suggestions que limit et écarte celles qui sont dehors, si bien qu'un rectangle peut en afficher moins que limit. Une coordonnée saisie est recherchée où qu'elle soit, et le rectangle ne la filtre pas.
  • proximity favorise les résultats près d'un point sans en exclure aucun : [lng, lat], ou "map" pour le centre de la carte au moment de chaque recherche. Elle est transmise à la passerelle sous le nom focus.
  • renderResult (Vue : l'emplacement result) dessine chaque option.
  • emptyText (Vue : empty-text) remplace ce qu'affiche la liste quand une recherche ne trouve rien. errorText (Vue : error-text) est une fonction qui reçoit l'erreur et renvoie ce qu'affiche la liste quand une recherche échoue, ligne hors du Canada comprise ; une erreur de la passerelle porte status et code. well-search et legal-land-search acceptent les deux. La ligne « Recherche... » suit lang.
"use client";
 
import { Geocoder } from "@/components/ui/geocoder";
import { Map } from "@/components/ui/map";
 
export function PlaceSearch() {
  const apiKey = process.env.NEXT_PUBLIC_UNMAP_KEY!;
  return (
    <div className="h-[560px]">
      <Map apiKey={apiKey} center={[-114.07, 51.05]} zoom={10}>
        <div className="absolute top-3 left-3 z-10 w-72">
          <Geocoder
            apiKey={apiKey}
            bbox={[-115.2, 50.8, -113.8, 51.4]}
            proximity="map"
            renderResult={(result) => (
              <span className="flex flex-col">
                <span>{result.name}</span>
                <span className="text-xs text-muted-foreground">{result.address?.region}</span>
              </span>
            )}
          />
        </div>
      </Map>
    </div>
  );
}
<script setup lang="ts">
import { UnmapMap } from "@/components/ui/map";
import { UnmapGeocoder } from "@/components/ui/geocoder";
 
const apiKey = import.meta.env.VITE_UNMAP_KEY;
</script>
 
<template>
  <UnmapMap :api-key="apiKey" :center="[-114.07, 51.05]" :zoom="10">
    <div class="absolute top-3 left-3 z-10 w-72">
      <UnmapGeocoder :api-key="apiKey" :bbox="[-115.2, 50.8, -113.8, 51.4]" proximity="map">
        <template #result="{ result }">
          <span class="flex flex-col">
            <span>{{ result.name }}</span>
            <span class="text-xs text-muted-foreground">{{ result.address?.region }}</span>
          </span>
        </template>
      </UnmapGeocoder>
    </div>
  </UnmapMap>
</template>

Panneau d'itinéraire

routing-panel résout une adresse de départ et une adresse d'arrivée avec le géocodeur, demande un itinéraire à l'API d'itinéraires et le trace avec route-line, qui s'installe avec lui. Une soumission fait deux recherches et un itinéraire, soit trois requêtes. mode vaut auto (par défaut), car, bicycle, pedestrian ou truck, et onRoute (Vue : @route) reçoit chaque itinéraire tracé : la ligne, sa distance en mètres et sa durée en secondes. Le panneau s'affiche comme un simple formulaire : l'exemple le place donc dans votre Card. Profil d'altitude passe cette ligne à elevation-profile.

"use client";
 
import { Card, CardContent } from "@/components/ui/card";
import { Map } from "@/components/ui/map";
import { RoutingPanel } from "@/components/ui/routing-panel";
 
export function Directions() {
  const apiKey = process.env.NEXT_PUBLIC_UNMAP_KEY!;
  return (
    <div className="h-[560px]">
      <Map apiKey={apiKey} center={[-114.07, 51.05]} zoom={11}>
        <Card className="absolute top-3 left-3 z-10 w-80">
          <CardContent>
            <RoutingPanel
              apiKey={apiKey}
              mode="bicycle"
              onRoute={(route) => console.log(route.distanceMeters, route.durationSeconds)}
            />
          </CardContent>
        </Card>
      </Map>
    </div>
  );
}
<script setup lang="ts">
import type { LngLat } from "@unmap/routing";
import { Card, CardContent } from "@/components/ui/card";
import { UnmapMap } from "@/components/ui/map";
import { UnmapRoutingPanel } from "@/components/ui/routing-panel";
 
const apiKey = import.meta.env.VITE_UNMAP_KEY!;
function onRoute(route: { coordinates: LngLat[]; distanceMeters: number; durationSeconds: number }) {
  console.log(route.distanceMeters, route.durationSeconds);
}
</script>
 
<template>
  <div class="h-[560px]">
    <UnmapMap :api-key="apiKey" :center="[-114.07, 51.05]" :zoom="11">
      <Card class="absolute top-3 left-3 z-10 w-80">
        <CardContent>
          <UnmapRoutingPanel :api-key="apiKey" mode="bicycle" @route="onRoute" />
        </CardContent>
      </Card>
    </UnmapMap>
  </div>
</template>