Aller au contenu

Utiliser les fonds de carte unmap avec mapcn

mapcn est un ensemble de composants cartographiques React à la manière de shadcn, bâtis sur MapLibre : un <Map>, des contrôles, des marqueurs, des fenêtres contextuelles et des tracés, copiés dans votre projet comme n'importe quel composant shadcn. unmap donne à ces composants un fond de carte conçu au Canada, en douze styles, avec des libellés en français sur demande. Tout le changement tient en deux URL de style passées à <Map>. Vos composants, vos marqueurs et vos couches restent exactement comme ils sont.

Installation

Ajoutez le composant de carte de mapcn. Il copie components/ui/map.tsx dans votre projet et installe maplibre-gl :

npx shadcn@latest add @mapcn/map

Obtenez ensuite une clé dans le tableau de bord et placez-la dans votre fichier d'environnement public :

# .env.local
NEXT_PUBLIC_UNMAP_KEY=um_live_...

Une clé utilisée par une carte dans un navigateur est lisible par quiconque charge la page, chez tous les fournisseurs de cartes. Restreignez-la à vos origines de production dans le tableau de bord plutôt que de tenter de la cacher, et servez-vous d'une clé um_test_ pendant le développement. Avec Vite, la même clé s'appelle VITE_UNMAP_KEY et se lit dans import.meta.env. Voir Authentification.

Brancher la carte sur unmap

Une petite fonction construit l'URL du style, pour que la clé et le nom du style vivent à un seul endroit :

// lib/unmap.ts
const key = process.env.NEXT_PUBLIC_UNMAP_KEY;
 
export function unmapStyle(mode: "light" | "dark", style = "base") {
  return `https://api.unmap.dev/styles/${style}.json?key=${key}&mode=${mode}`;
}

Passez une URL par mode à la propriété styles de mapcn :

// components/city-map.tsx
import { Map, MapControls } from "@/components/ui/map";
import { unmapStyle } from "@/lib/unmap";
 
const styles = { light: unmapStyle("light"), dark: unmapStyle("dark") };
 
export function CityMap() {
  return (
    <div className="h-[420px] w-full">
      <Map styles={styles} center={[-114.0719, 51.0447]} zoom={11}>
        <MapControls />
      </Map>
    </div>
  );
}

C'est toute l'intégration. mapcn choisit le mode lui-même : il surveille une classe dark ou light, ou un attribut data-theme, sur <html>, se rabat sur la préférence du système d'exploitation, et passe d'une URL à l'autre quand l'une ou l'autre change. center et zoom sont des options MapLibre que <Map> transmet telles quelles.

Aucun transformRequest à écrire. La passerelle recopie la clé qui a servi à charger le style dans chaque URL de tuile, de glyphe et de sprite qu'il contient, donc MapLibre authentifie chaque requête de lui-même.

L'URL accepte tout le reste de ce qu'une carte unmap sait faire :

  • Style. base est le style par défaut. Les autres sont muted, outdoor, blueprint, blush, orchid, canopy, lagoon, tropic, sunset, bold et pastel, chacun dans les deux modes : unmapStyle("dark", "outdoor") donne une carte outdoor en mode sombre. Ils sont tous décrits dans l'API de cartes.
  • Langue. Ajoutez &lang=fr pour des libellés en français. Sans ce paramètre, la passerelle lit l'Accept-Language du navigateur : une personne dont le navigateur préfère le français obtient des libellés en français sans une ligne de code.
  • Thème. Ajoutez &theme=<code> avec un code tiré de /create pour appliquer votre propre cartographie. Cela n'a rien à voir avec la propriété theme de mapcn, qui force son choix entre clair et sombre.

Le style porte sa propre attribution (unmap et les contributeurs d'OpenStreetMap), et le contrôle d'attribution compact de mapcn l'affiche. Gardez-la visible : la licence d'OpenStreetMap l'exige.

Si votre site envoie une politique de sécurité du contenu (CSP) stricte, ajoutez https://api.unmap.dev à connect-src, à côté des entrées pour le worker que liste la page d'installation de mapcn.

Itinéraires et recherche

Le <MapRoute> de mapcn trace n'importe quelle liste de paires [lng, lat], et ses marqueurs prennent une longitude et une latitude. Les clients typés d'unmap renvoient exactement cela : vous gardez les composants de mapcn et appelez les nôtres pour les données.

npm i @unmap/routing @unmap/geocoding

Dans une page App Router de Next.js, un Server Component peut faire les deux appels avant son rendu :

// app/directions/page.tsx
import { Geocoder } from "@unmap/geocoding";
import { Router } from "@unmap/routing";
import { Map, MapControls, MapMarker, MarkerContent, MarkerPopup, MapRoute } from "@/components/ui/map";
import { unmapStyle } from "@/lib/unmap";
 
// Server-side calls send no Origin header, so they use an unrestricted server key.
const key = process.env.UNMAP_API_KEY ?? "";
const geocoder = new Geocoder({ key });
const router = new Router({ key });
 
export default async function Directions() {
  const [[from], [to]] = await Promise.all([
    geocoder.search("Calgary Tower", { limit: 1 }),
    geocoder.search("Calgary Zoo", { limit: 1 }),
  ]);
  const route = await router.route([from.lng, from.lat], [to.lng, to.lat], { mode: "auto" });
 
  return (
    <div className="h-[420px] w-full">
      <Map styles={{ light: unmapStyle("light"), dark: unmapStyle("dark") }} center={[from.lng, from.lat]} zoom={12}>
        <MapRoute coordinates={route.geometry.coordinates} />
        {[from, to].map((place) => (
          <MapMarker key={place.id} longitude={place.lng} latitude={place.lat}>
            <MarkerContent />
            <MarkerPopup>{place.name}</MarkerPopup>
          </MapMarker>
        ))}
        <MapControls />
      </Map>
    </div>
  );
}

route.geometry est une LineString GeoJSON : ses coordinates vont dans <MapRoute> sans transformation. Chaque résultat de géocodage porte id, name, lng et lat, et geocoder.autocomplete(q) renvoie la même forme pour une boîte de recherche. Ne mettez jamais cette clé serveur dans une variable NEXT_PUBLIC_. Hors de Next.js, ou dans un composant client, faites les deux mêmes appels dans un effet, avec la clé du navigateur.

mode accepte aussi car, bicycle, pedestrian et truck. Les pages API d'itinéraires et API de géocodage décrivent toutes les options.

Ce que coûte une requête

unmap facture à la requête. Chaque document de style compte pour un appel, tout comme chaque tuile, chaque requête de géocodage et chaque itinéraire; les glyphes et les sprites ne sont jamais facturés. Une carte qui charge 40 tuiles coûte 40 appels, autant que 40 frappes de saisie semi-automatique, et passer du mode clair au mode sombre charge l'autre document de style. Les requêtes venant de localhost et des autres origines dev sont comptées, mais jamais facturées. Un domaine en production demande un forfait payant, puisqu'une clé Hobby n'accepte que des origines dev. Les chiffres sont dans Forfaits et limites.

Le fond de carte par défaut de mapcn est celui de CARTO. Le README de mapcn précise qu'un usage commercial des fonds de carte CARTO exige une licence CARTO Enterprise; les détails sont dans les conditions des fonds de carte de CARTO. Passer vos propres styles, comme ci-dessus, remplace entièrement ce fond par défaut.

Quand choisir plutôt le registre unmap

mapcn convient bien quand vous voulez ses composants et qu'il ne vous manque qu'un fond de carte. unmap publie aussi son propre registre shadcn à registry.unmap.dev, et il convient mieux dans ces cas :

  • Vous développez en Vue ou en Nuxt. mapcn ne fait que du React. Le registre unmap a une voie shadcn-vue avec les mêmes éléments.
  • Vous voulez la recherche et les itinéraires tout faits. Les éléments geocoder et routing-panel sont déjà branchés sur la passerelle, sur vos propres Combobox, Field, Input, Button et Alert de shadcn.
  • Vous voulez que la carte suive votre système de design. Les contrôles et les fenêtres contextuelles de MapLibre prennent vos jetons, les marqueurs et les tracés utilisent par défaut votre --primary, et le style et le thème sont des propriétés plutôt qu'une URL à construire.

Commencez par npx @unmap/cli add map. Composants donne la liste complète et les deux façons d'installer.