Aller au contenu

Depuis HERE

HERE, c'est un objet plateforme, un ensemble de classes de carte JavaScript, et une famille d'API REST (Geocoding & Search v7, Routing v8, Isoline). unmap, c'est une clé et trois clients. Les métiers se correspondent nettement. Le modèle objet non : vous jetterez H.Map, H.service.Platform et la boîte à outils d'interface HERE.

Restez sur HERE s'il vous faut une couverture hors du Canada, les extras flotte de HERE (péages, trafic en direct comme produit, itinéraires VE), ou une carte qui n'est pas une carte vectorielle GL. L'itinéraire camion existe des deux côtés ; le profil camion d'unmap est documenté sur l'API d'itinéraires et n'est bon que dans la mesure des balises de restriction d'OpenStreetMap.

npm i @unmap/sdk

La carte

HERE construit un Platform, lui demande une couche par défaut, puis construit un H.Map. unmap construit la carte en un appel.

const platform = new H.service.Platform({ apikey: "HERE_API_KEY" });
const layers = platform.createDefaultLayers();
const map = new H.Map(document.getElementById("map"), layers.vector.normal.map, {
  center: { lat: 51.0447, lng: -114.0719 },
  zoom: 11,
});
new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
H.ui.UI.createDefault(map, layers);
import { Unmap } from "@unmap/sdk";
 
const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.0719, 51.0447],
  zoom: 11,
});
résultat en direct
le code qui l’a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.0719, 51.0447],
  zoom: 11,
});

Le vector.normal.map de HERE est style: "base". Les couches nuit et gris sont mode: "dark" et style: "muted". Il n'y a pas de couche satellite. Le zoom et la boussole atterrissent sur la carte par défaut ; controls: false les enlève.

L'API JS de HERE prend { lat, lng }. unmap prend [lng, lat]. Le REST HERE a aussi tendance à écrire lat,lng (at=51.04,-114.07). Inversez les deux.

Repères

H.map.Marker plus H.ui.InfoBubble deviennent Marker et Popup MapLibre.

const marker = new H.map.Marker({ lat: 51.0447, lng: -114.0719 });
map.addObject(marker);
import { maplibregl } from "@unmap/sdk";
 
new maplibregl.Marker()
  .setLngLat([-114.0719, 51.0447])
  .setPopup(new maplibregl.Popup().setHTML("<p>Calgary Tower</p>"))
  .addTo(unmap.map!);
résultat en direct
le code qui l’a produit
import { Unmap, maplibregl } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.0719, 51.0447],
  zoom: 11,
});

const [place] = await unmap.geocoder.search("Calgary Tower");

new maplibregl.Marker({ color: "#FF3E9A" })
  .setLngLat([place.lng, place.lat])
  .setPopup(new maplibregl.Popup().setText(place.name))
  .addTo(unmap.map!);

map.addObject / map.removeObject deviennent marker.addTo(map) / marker.remove(). Un groupe de repères est une source GeoJSON, pas un H.map.Group.

Géocodage et saisie semi-automatique

HERE Geocoding & Search v7 (/v1/geocode, /v1/autosuggest, /v1/revgeocode, /v1/browse) deviennent quatre méthodes sur unmap.geocoder. Les at et in de HERE sont near et bbox, et l'ordre des coordonnées s'inverse.

const url = new URL("https://geocode.search.hereapi.com/v1/geocode");
url.searchParams.set("q", "Calgary Tower");
url.searchParams.set("apiKey", "HERE_API_KEY");
const data = await (await fetch(url)).json();
const { lat, lng } = data.items[0].position;
map.setCenter({ lat, lng });
const results = await unmap.geocoder.search("Calgary Tower");
const [first] = results;
if (first) unmap.map!.setCenter([first.lng, first.lat]);
const hints = await unmap.geocoder.autocomplete("calgary tow", { limit: 5 });
const here = await unmap.geocoder.reverse(-114.07, 51.05);
const nearby = await unmap.geocoder.nearby("pharmacy", {
  near: [-114.07, 51.05],
  radius: 1000,
});
résultat en direct
le code qui l’a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({ key: "um_live_..." });

const results = await unmap.geocoder.search("Calgary Tower", { limit: 3 });

Les items HERE portent id, title, address, position, et un bloc riche categories / contacts / openingHours lorsque Discover ou Browse touche un POI. Les résultats unmap portent id, name, layer, lng, lat, names, et un address plat. Il n'y a pas de contacts, d'heures, ni d'identifiants HERE à faire aller-retour. La navigation par catégorie est nearby. L'API de géocodage est le contrat.

Itinéraires et isolignes

HERE Routing v8 (/v8/routes) et Isoline deviennent router.route et router.isochrone. Le codec de polyligne HERE disparaît : la géométrie est du GeoJSON.

const url = new URL("https://router.hereapi.com/v8/routes");
url.searchParams.set("origin", "51.0447,-114.0719");
url.searchParams.set("destination", "51.0899,-113.9871");
url.searchParams.set("transportMode", "car");
url.searchParams.set("return", "polyline,summary");
url.searchParams.set("apiKey", "HERE_API_KEY");
const data = await (await fetch(url)).json();
const route = await unmap.router.route([-114.0719, 51.0447], [-113.9871, 51.0899], {
  mode: "auto",
});
 
unmap.map!.addSource("route", {
  type: "geojson",
  data: { type: "Feature", properties: {}, geometry: route.geometry },
});
unmap.map!.addLayer({
  id: "route",
  type: "line",
  source: "route",
  paint: { "line-color": "#3887be", "line-width": 4 },
});
résultat en direct
le code qui l’a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  center: [-114.03, 51.07],
  zoom: 11,
});

const route = await unmap.router.route([-114.0719, 51.0447], [-113.9871, 51.0899], { mode: "auto" });

unmap.map!.on("load", () => {
  unmap.map!.addSource("route", {
    type: "geojson",
    data: { type: "Feature", properties: {}, geometry: route.geometry },
  });
  unmap.map!.addLayer({
    id: "route-line",
    type: "line",
    source: "route",
    layout: { "line-cap": "round", "line-join": "round" },
    paint: { "line-color": "#FF3E9A", "line-width": 3 },
  });
});

transportMode=car est auto. pedestrian et bicycle gardent ces noms. truck prend un profil de véhicule en mètres et en tonnes (height, width, length, weight, …), pas les kilogrammes truck[grossWeight] de HERE. Il n'y a pas de points intermédiaires, pas de return=polyline à demander, et pas de flexible-polyline à décoder.

L'isoligne est la même idée que l'API Isoline de HERE, avec une surface plus petite : jusqu'à quatre contours, 120 minutes chacun.

const bands = await unmap.router.isochrone([-114.07, 51.05], {
  minutes: [10, 20],
  mode: "auto",
});

Ce qui n'a pas d'équivalent

  • Couverture hors du Canada.
  • Trafic en direct comme produit, péages, VE et transport en commun. Le camion existe ; ce sont des balises OSM, pas une vérification de permis.
  • Identifiants HERE, contacts, heures d'ouverture et photos de lieux.
  • La boîte à outils d'interface HERE et H.service.Platform.
  • Itinéraires à points de passage, matrice et télématique de flotte.
  • Imagerie satellite.

Liste de vérification

  • Clé API HERE remplacée par um_live_... / um_test_...
  • { lat, lng } et paramètres lat,lng inversés en [lng, lat]
  • H.Map remplacé par new Unmap({ container, ... })
  • Géocodage, autosuggest, revgeocode et browse pointés vers unmap.geocoder
  • Routing v8 et Isoline pointés vers unmap.router, avec la ligne dessinée en GeoJSON
  • Décodage de flexible-polyline supprimé
  • Fonctions réservées à la flotte abandonnées ou laissées chez HERE
  • Origine configurée pour le trafic de production (Forfaits et limites)

Le Guide de démarrage est la même carte construite de zéro. Les défauts du camion et les limites des données de restriction OSM sont sur l'API d'itinéraires.