@unmap/deck 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { Map } from 'maplibre-gl';
|
|
|
13
13
|
type LngLatZ = [number, number, number];
|
|
14
14
|
/** One aerial lift, baked in 3D. */
|
|
15
15
|
interface Lift3d {
|
|
16
|
-
/** Stable OSM-derived id, such as `
|
|
16
|
+
/** Stable OSM-derived id, such as `way-123` (the OSM way). */
|
|
17
17
|
id: string;
|
|
18
18
|
name: string | null;
|
|
19
19
|
/** The OSM `aerialway=*` value: `chair_lift`, `gondola`, `t-bar`, `cable_car`, … */
|
package/dist/index.js
CHANGED
|
@@ -210,10 +210,20 @@ function createDeckOverlay(map, opts = {}) {
|
|
|
210
210
|
const overlay = new MapLibreOverlay({ ...opts, interleaved: true });
|
|
211
211
|
map.addControl(overlay);
|
|
212
212
|
let removed = false;
|
|
213
|
+
let layers = opts.layers ?? [];
|
|
214
|
+
const reapplyWhenIdle = () => {
|
|
215
|
+
if (removed || map.isStyleLoaded()) return;
|
|
216
|
+
map.once("idle", () => {
|
|
217
|
+
if (!removed) overlay.setProps({ layers });
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
reapplyWhenIdle();
|
|
213
221
|
return {
|
|
214
222
|
overlay,
|
|
215
|
-
setLayers(
|
|
223
|
+
setLayers(next) {
|
|
224
|
+
layers = next;
|
|
216
225
|
overlay.setProps({ layers });
|
|
226
|
+
reapplyWhenIdle();
|
|
217
227
|
},
|
|
218
228
|
remove() {
|
|
219
229
|
if (removed) return;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/geometry.ts","../src/options.ts","../src/fetch.ts","../src/layers.ts","../src/overlay.ts","../src/index.ts"],"sourcesContent":["import type { LngLatZ } from \"./types\";\n\n/**\n * The height to draw a baked point at, on a map whose terrain has this vertical exaggeration.\n *\n * MapLibre draws terrain at `DEM height × exaggeration`, measured from sea level (no offset), and\n * deck.gl layers are not draped on that terrain: they sit at whatever z they are given. A baked z\n * therefore has to be scaled by the same factor to stay on the terrain the map draws. At the\n * default exaggeration of 1 the baked z is returned as is.\n *\n * The whole height is scaled, including the part that is above the ground (a tower, the cable's\n * clearance), because the lifts document carries one z per point, not ground plus offset. At 1.5×\n * a 12 m tower draws 18 m tall: still on the ground at its foot, just taller. Read the map's own\n * value with `map.getTerrain()?.exaggeration ?? 1`.\n */\nexport function bakedZ(point: LngLatZ, exaggeration = 1): number {\n if (!(Number.isFinite(exaggeration) && exaggeration > 0)) {\n throw new RangeError(`exaggeration must be a positive number, got ${exaggeration}`);\n }\n return (point[2] ?? 0) * exaggeration;\n}\n\n/** `point` with its z scaled by `exaggeration`; lng and lat untouched. */\nexport function scaled(point: LngLatZ, exaggeration: number): LngLatZ {\n return [point[0], point[1], bakedZ(point, exaggeration)];\n}\n\nconst RAD = Math.PI / 180;\n\n/** Initial great-circle bearing from `a` to `b`, degrees clockwise from north, in [0, 360). */\nexport function bearing(a: readonly number[], b: readonly number[]): number {\n const [lng1 = 0, lat1 = 0] = a;\n const [lng2 = 0, lat2 = 0] = b;\n const φ1 = lat1 * RAD;\n const φ2 = lat2 * RAD;\n const Δλ = (lng2 - lng1) * RAD;\n const y = Math.sin(Δλ) * Math.cos(φ2);\n const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ);\n return ((Math.atan2(y, x) / RAD) + 360) % 360;\n}\n\n/** Squared planar distance from `p` to segment `a`–`b`, in degrees with longitude scaled by cos(lat). */\nexport function segmentDistance2(p: readonly number[], a: readonly number[], b: readonly number[]): number {\n const k = Math.cos((p[1] ?? 0) * RAD);\n const px = (p[0] ?? 0) * k, py = p[1] ?? 0;\n const ax = (a[0] ?? 0) * k, ay = a[1] ?? 0;\n const bx = (b[0] ?? 0) * k, by = b[1] ?? 0;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / len2));\n const cx = ax + t * dx - px, cy = ay + t * dy - py;\n return cx * cx + cy * cy;\n}\n","/**\n * MapLibre options `@unmap/deck` needs at construction time. Pass them as `createMap`'s\n * `maplibre` option (or spread them into `new maplibregl.Map({...})`).\n *\n * MapLibre creates its WebGL context with `antialias: false`, which gives deck.gl's lift cables\n * hard, stair-stepped edges. Antialiasing is a context attribute, so it can only be chosen when\n * the map is created; `createDeckOverlay` cannot turn it on later and warns instead.\n */\nexport const deckMapOptions: { canvasContextAttributes: { antialias: true } } = {\n canvasContextAttributes: { antialias: true },\n};\n","import { DEFAULT_GATEWAY, UnmapError, parseRetryAfter } from \"@unmap/core\";\nimport type { Lifts3dDocument } from \"./types\";\n\n/** The only document schema this package reads. */\nexport const LIFTS_3D_SCHEMA = \"unmap.ski-lifts-3d.v1\";\n\n/**\n * A lifts-3D failure: a non-2xx answer from the gateway (`status` and `code` from it, such as\n * `403 addon_required` for a key without the ski add-on), or a body that is not a\n * `unmap.ski-lifts-3d.v1` document (`code: \"schema_mismatch\"`).\n *\n * Extends `UnmapError`, so one `instanceof UnmapError` catches it with every other unmap error.\n */\nexport class Lifts3dError extends UnmapError {\n constructor(status: number, message: string, code?: string, retryAfterSeconds?: number) {\n super(status, message, code, retryAfterSeconds);\n this.name = \"Lifts3dError\";\n }\n}\n\nexport interface FetchLifts3dOptions {\n /** An unmap key with the `ski` add-on. It is sent to `gateway` and nowhere else. */\n key: string;\n /** A ski area id from `/ski/areas`, such as `osm-way-123`. */\n areaId: string;\n /** Gateway origin; defaults to `https://api.unmap.dev`. */\n gateway?: string;\n /** A `fetch` to use instead of the global one. */\n fetch?: typeof fetch;\n signal?: AbortSignal;\n}\n\n/**\n * Fetch an area's baked 3D lifts (`GET /ski/areas/{id}/lifts-3d`).\n *\n * The data sits behind the `ski` add-on; the renderers in this package do not. The document's z\n * values are metres above sea level from `terrain_release`, ready for `liftCablesLayer` and\n * `liftModelsLayer`.\n */\nexport async function fetchLifts3d(opts: FetchLifts3dOptions): Promise<Lifts3dDocument> {\n if (!opts.key) throw new Lifts3dError(400, \"fetchLifts3d needs a key\");\n if (!opts.areaId) throw new Lifts3dError(400, \"fetchLifts3d needs an areaId\");\n const base = (opts.gateway ?? DEFAULT_GATEWAY).replace(/\\/+$/, \"\");\n const url = `${base}/ski/areas/${encodeURIComponent(opts.areaId)}/lifts-3d?${new URLSearchParams({ key: opts.key })}`;\n // Bound to globalThis: a bare `fetch` called with another receiver is rejected by browsers.\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n const res = await fetchImpl(url, { signal: opts.signal, headers: { accept: \"application/json\" } });\n\n if (!res.ok) {\n const fallback = `lifts-3d ${res.status}`;\n let body: { error?: unknown; code?: unknown } | undefined;\n try {\n body = (await res.json()) as { error?: unknown; code?: unknown };\n } catch {\n body = undefined;\n }\n const reason = typeof body?.error === \"string\" ? body.error : undefined;\n const code = typeof body?.code === \"string\" ? body.code : undefined;\n const retryAfter = parseRetryAfter(res.headers?.get(\"retry-after\") ?? null) ?? undefined;\n throw new Lifts3dError(res.status, reason ? `${reason} (${fallback})` : fallback, code, retryAfter);\n }\n\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Lifts3dError(res.status, \"lifts-3d answered with a body that is not JSON\", \"schema_mismatch\");\n }\n // The gateway answers with the ski routes' `{ data, meta }` envelope; the release is meta's\n // data_version. The document callers get back is flat.\n const envelope = body as { data?: Record<string, unknown>; meta?: { data_version?: unknown } } | null;\n const data = envelope && typeof envelope === \"object\" ? envelope.data : undefined;\n const flat = data ? { ...data, release: envelope?.meta?.data_version } : undefined;\n if (!isLifts3dDocument(flat)) {\n const got = data && \"schema\" in data ? String(data.schema) : \"no schema\";\n throw new Lifts3dError(res.status, `lifts-3d answered with ${got}; this client reads ${LIFTS_3D_SCHEMA}`, \"schema_mismatch\");\n }\n return { schema: flat.schema, release: flat.release, terrain_release: flat.terrain_release, area_id: flat.area_id, lifts: flat.lifts };\n}\n\nfunction isLifts3dDocument(body: unknown): body is Lifts3dDocument {\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) return false;\n const doc = body as Record<string, unknown>;\n return doc.schema === LIFTS_3D_SCHEMA && Array.isArray(doc.lifts) && typeof doc.release === \"string\"\n && typeof doc.area_id === \"string\" && typeof doc.terrain_release === \"string\";\n}\n","import { PathLayer, type PathLayerProps } from \"@deck.gl/layers\";\nimport { ScenegraphLayer, type ScenegraphLayerProps } from \"@deck.gl/mesh-layers\";\nimport { bearing, scaled, segmentDistance2 } from \"./geometry\";\nimport type { Lift3d, Lifts3dDocument, LngLatZ, RGBA } from \"./types\";\n\n/** A lifts document, or just its `lifts`. */\nexport type LiftsInput = Lifts3dDocument | readonly Lift3d[];\n\nconst liftsOf = (input: LiftsInput): Lift3d[] =>\n (Array.isArray(input) ? input : (input as Lifts3dDocument).lifts) as Lift3d[];\n\n/** Known OSM `aerialway=*` values, plus `default` for anything else. */\nexport type LiftColorKey =\n | \"cable_car\"\n | \"gondola\"\n | \"mixed_lift\"\n | \"chair_lift\"\n | \"drag_lift\"\n | \"t-bar\"\n | \"j-bar\"\n | \"platter\"\n | \"rope_tow\"\n | \"magic_carpet\"\n | \"zip_line\"\n | \"goods\"\n | \"default\";\n\n/**\n * Cable colour by aerialway. Dark, cool and unsaturated so a cable reads as steel against the\n * winter style's snow; enclosed cabins (gondola, cable car) in blue, surface lifts in brown.\n * Magenta is the interface accent and stays out.\n */\nexport const LIFT_COLORS: Readonly<Record<LiftColorKey, RGBA>> = {\n cable_car: [13, 71, 161, 255],\n gondola: [30, 96, 180, 255],\n mixed_lift: [55, 71, 79, 255],\n chair_lift: [38, 50, 56, 255],\n drag_lift: [109, 76, 65, 255],\n \"t-bar\": [109, 76, 65, 255],\n \"j-bar\": [109, 76, 65, 255],\n platter: [109, 76, 65, 255],\n rope_tow: [141, 110, 99, 255],\n magic_carpet: [96, 125, 139, 255],\n zip_line: [0, 105, 92, 255],\n goods: [97, 97, 97, 255],\n default: [66, 66, 66, 255],\n};\n\nexport interface LiftCablesLayerOptions {\n /** Layer id. Defaults to `unmap-lift-cables`; keep it stable so deck.gl diffs instead of rebuilding. */\n id?: string;\n /**\n * The map's terrain exaggeration (`map.getTerrain()?.exaggeration ?? 1`). Every baked z is\n * multiplied by it, from sea level, as MapLibre multiplies the DEM; see `bakedZ`. Default 1.\n */\n exaggeration?: number;\n /** Cable width in `widthUnits`. Default 2. */\n width?: number;\n /** `pixels` (the default) keeps cables legible at every zoom; `meters` makes them real-sized. */\n widthUnits?: \"pixels\" | \"meters\" | \"common\";\n /** Colours per aerialway, merged over `LIFT_COLORS`. */\n colors?: Partial<Record<string, RGBA>>;\n /** Pick lifts on hover and click. Default false. */\n pickable?: boolean;\n /** MapLibre layer id to draw beneath (interleaved mode), e.g. the first label layer. */\n beforeId?: string;\n}\n\n/**\n * A deck.gl `PathLayer` drawing each lift's `cable` in 3D at its baked height.\n *\n * Heights are baked by the pipeline and never queried at render time: deck.gl layers do not drape\n * on MapLibre terrain, so the z in the file is the only thing that puts a cable on the mountain.\n */\nexport function liftCablesLayer(input: LiftsInput, opts: LiftCablesLayerOptions = {}): PathLayer<Lift3d> {\n const exaggeration = opts.exaggeration ?? 1;\n const colors = { ...LIFT_COLORS, ...opts.colors } as Record<string, RGBA | undefined>;\n const props: PathLayerProps<Lift3d> = {\n id: opts.id ?? \"unmap-lift-cables\",\n data: liftsOf(input),\n positionFormat: \"XYZ\",\n getPath: (lift) => lift.cable.map((p) => scaled(p, exaggeration)),\n getColor: (lift) => colors[lift.aerialway] ?? colors.default ?? LIFT_COLORS.default,\n getWidth: opts.width ?? 2,\n widthUnits: opts.widthUnits ?? \"pixels\",\n widthMinPixels: 1,\n // Cables are seen from every pitch; billboarding keeps a thin line from vanishing edge-on.\n billboard: true,\n capRounded: true,\n jointRounded: true,\n pickable: opts.pickable ?? false,\n updateTriggers: {\n getPath: [exaggeration],\n getColor: [JSON.stringify(opts.colors ?? {})],\n },\n };\n // `beforeId` is read by @deck.gl/maplibre in interleaved mode, not declared on PathLayerProps.\n return new PathLayer<Lift3d>(opts.beforeId ? { ...props, beforeId: opts.beforeId } as PathLayerProps<Lift3d> : props);\n}\n\n/** What a model stands for. `station` is both terminals; `pylon` is every tower. */\nexport type LiftModelKind = \"pylon\" | \"station\";\n\n/** One placed model: a station or a pylon of one lift. */\nexport interface LiftModelInstance {\n /** `<liftId>:<kind>:<index>`, stable across releases while OSM ids are. */\n id: string;\n liftId: string;\n aerialway: string;\n kind: LiftModelKind;\n index: number;\n /** Baked position with z already scaled by the exaggeration. */\n position: LngLatZ;\n /** Direction of the line at this point, degrees clockwise from north. */\n bearing: number;\n}\n\n/** The bearing of the cable segment nearest to `p`, or of the station line if there is no cable. */\nfunction lineBearingAt(lift: Lift3d, p: LngLatZ): number {\n const line = lift.cable.length >= 2 ? lift.cable : lift.stations;\n let best = Infinity;\n let at = bearing(lift.stations[0], lift.stations[1]);\n for (let i = 1; i < line.length; i++) {\n const a = line[i - 1]!;\n const b = line[i]!;\n const d = segmentDistance2(p, a, b);\n if (d < best && (a[0] !== b[0] || a[1] !== b[1])) {\n best = d;\n at = bearing(a, b);\n }\n }\n return at;\n}\n\n/**\n * Every station and pylon as a model instance, oriented along its lift. Exposed so a caller can\n * build their own layer (or a label layer) over the same points `liftModelsLayer` draws.\n */\nexport function liftModelInstances(input: LiftsInput, exaggeration = 1): LiftModelInstance[] {\n const out: LiftModelInstance[] = [];\n for (const lift of liftsOf(input)) {\n const add = (kind: LiftModelKind, points: readonly LngLatZ[]) =>\n points.forEach((p, index) =>\n out.push({\n id: `${lift.id}:${kind}:${index}`,\n liftId: lift.id,\n aerialway: lift.aerialway,\n kind,\n index,\n position: scaled(p, exaggeration),\n bearing: lineBearingAt(lift, p),\n }),\n );\n add(\"station\", lift.stations);\n add(\"pylon\", lift.pylons);\n }\n return out;\n}\n\nexport interface LiftModelsLayerOptions {\n /**\n * glTF/GLB URL per kind. Supplied by the caller; this package bundles no models. A kind with no\n * URL is not drawn.\n */\n models: Partial<Record<LiftModelKind, string>>;\n /** Id prefix; each layer is `<id>-<kind>`. Defaults to `unmap-lift-models`. */\n id?: string;\n /** The map's terrain exaggeration, as for `liftCablesLayer`. Default 1. */\n exaggeration?: number;\n /** Model units to metres. Default 1 (models authored in metres). */\n sizeScale?: number;\n /** Extra yaw in degrees, for a model authored facing another way. Default 0. */\n yawOffset?: number;\n pickable?: boolean;\n beforeId?: string;\n}\n\nconst KINDS: readonly LiftModelKind[] = [\"pylon\", \"station\"];\n\n/**\n * deck.gl `ScenegraphLayer`s placing a model at each pylon and station, one layer per kind that\n * has a URL in `models` (a ScenegraphLayer draws one scenegraph).\n *\n * The model origin goes at the baked point. Models are glTF (Y up), so they are rolled 90° onto\n * deck.gl's Z up, and yawed by `-bearing` so the model's forward axis runs up the line.\n */\nexport function liftModelsLayer(input: LiftsInput, opts: LiftModelsLayerOptions): ScenegraphLayer<LiftModelInstance>[] {\n const exaggeration = opts.exaggeration ?? 1;\n const yawOffset = opts.yawOffset ?? 0;\n const prefix = opts.id ?? \"unmap-lift-models\";\n const all = liftModelInstances(input, exaggeration);\n const layers: ScenegraphLayer<LiftModelInstance>[] = [];\n for (const kind of KINDS) {\n const url = opts.models[kind];\n if (!url) continue;\n const props: ScenegraphLayerProps<LiftModelInstance> = {\n id: `${prefix}-${kind}`,\n data: all.filter((i) => i.kind === kind),\n scenegraph: url,\n getPosition: (i) => i.position,\n getOrientation: (i) => [0, -i.bearing + yawOffset, 90],\n sizeScale: opts.sizeScale ?? 1,\n _lighting: \"pbr\",\n pickable: opts.pickable ?? false,\n updateTriggers: { getOrientation: [yawOffset] },\n };\n layers.push(\n new ScenegraphLayer<LiftModelInstance>(\n opts.beforeId ? ({ ...props, beforeId: opts.beforeId } as ScenegraphLayerProps<LiftModelInstance>) : props,\n ),\n );\n }\n return layers;\n}\n","import { MapLibreOverlay, type MapLibreOverlayProps } from \"@deck.gl/maplibre\";\nimport type { LayersList } from \"@deck.gl/core\";\nimport type { Map as MaplibreMap } from \"maplibre-gl\";\n\n/** The map `createDeckOverlay` takes: a MapLibre `Map`, such as `createMap` returns. */\nexport type DeckOverlayMap = MaplibreMap;\n\n/** Overlay props, less `interleaved`: this package always shares MapLibre's WebGL context. */\nexport type DeckOverlayOptions = Omit<MapLibreOverlayProps, \"interleaved\">;\n\nexport interface DeckOverlay {\n /** The underlying `MapLibreOverlay`, for picking (`pickObject`) or any other deck.gl prop. */\n readonly overlay: MapLibreOverlay;\n /** Replace the drawn layers. Keep layer ids stable so deck.gl diffs rather than rebuilds. */\n setLayers(layers: LayersList): void;\n /** Take the overlay off the map and release its GPU resources. Safe to call twice. */\n remove(): void;\n}\n\nconst warned = new WeakSet<object>();\n\n/**\n * Whether the map's WebGL context was created with antialiasing. `undefined` when it cannot be\n * told (no WebGL2 context yet). Reads the context the map already made: `getContext` with the\n * same type returns the existing one and never creates a second.\n */\nfunction antialiased(map: DeckOverlayMap): boolean | undefined {\n const gl = map.getCanvas().getContext(\"webgl2\");\n return gl?.getContextAttributes()?.antialias;\n}\n\n/**\n * Add a deck.gl overlay to a MapLibre map, interleaved: deck.gl draws into MapLibre's own WebGL\n * context and layer stack (one context, depth shared with the terrain), never a second canvas.\n *\n * Create the map with `deckMapOptions` for smooth cables; antialiasing cannot be switched on after\n * the map exists, so this warns once per map when it is off.\n *\n * const deck = createDeckOverlay(map, { layers: [liftCablesLayer(lifts)] });\n * deck.setLayers([...]);\n * deck.remove();\n */\nexport function createDeckOverlay(map: DeckOverlayMap, opts: DeckOverlayOptions = {}): DeckOverlay {\n if (antialiased(map) === false && !warned.has(map)) {\n warned.add(map);\n console.warn(\n \"@unmap/deck: this map was created without antialiasing, so deck.gl lines will draw with hard \" +\n \"edges. Create it with `maplibre: deckMapOptions` (createMap) or spread `deckMapOptions` into \" +\n \"the MapLibre Map options.\",\n );\n }\n const overlay = new MapLibreOverlay({ ...opts, interleaved: true });\n map.addControl(overlay);\n let removed = false;\n return {\n overlay,\n setLayers(layers) {\n overlay.setProps({ layers });\n },\n remove() {\n if (removed) return;\n removed = true;\n map.removeControl(overlay);\n },\n };\n}\n","/**\n * @unmap/deck: deck.gl layers for unmap maps, interleaved in MapLibre's WebGL context.\n *\n * Optional and separate from @unmap/maps, so a plain map never loads deck.gl. `fetchLifts3d`,\n * `bakedZ` and `deckMapOptions` import no renderer, and the package is `sideEffects: false`, so a\n * bundler drops deck.gl from a chunk that uses only them; load the layers with a dynamic\n * `import(\"@unmap/deck\")` when the user turns 3D on.\n */\nexport type { Lift3d, Lifts3dDocument, LngLatZ, RGBA } from \"./types\";\nexport { bakedZ } from \"./geometry\";\nexport { deckMapOptions } from \"./options\";\nexport { LIFTS_3D_SCHEMA, Lifts3dError, fetchLifts3d, type FetchLifts3dOptions } from \"./fetch\";\nexport {\n LIFT_COLORS,\n liftCablesLayer,\n liftModelInstances,\n liftModelsLayer,\n type LiftCablesLayerOptions,\n type LiftColorKey,\n type LiftModelInstance,\n type LiftModelKind,\n type LiftModelsLayerOptions,\n type LiftsInput,\n} from \"./layers\";\nexport { createDeckOverlay, type DeckOverlay, type DeckOverlayMap, type DeckOverlayOptions } from \"./overlay\";\n\n// Re-exported so `catch (e) { if (e instanceof UnmapError) }` works without adding @unmap/core.\nexport { UnmapError } from \"@unmap/core\";\n"],"mappings":";AAeO,SAAS,OAAO,OAAgB,eAAe,GAAW;AAC/D,MAAI,EAAE,OAAO,SAAS,YAAY,KAAK,eAAe,IAAI;AACxD,UAAM,IAAI,WAAW,+CAA+C,YAAY,EAAE;AAAA,EACpF;AACA,UAAQ,MAAM,CAAC,KAAK,KAAK;AAC3B;AAGO,SAAS,OAAO,OAAgB,cAA+B;AACpE,SAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,OAAO,OAAO,YAAY,CAAC;AACzD;AAEA,IAAM,MAAM,KAAK,KAAK;AAGf,SAAS,QAAQ,GAAsB,GAA8B;AAC1E,QAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI;AAC7B,QAAM,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI;AAC7B,QAAM,UAAK,OAAO;AAClB,QAAM,UAAK,OAAO;AAClB,QAAM,gBAAM,OAAO,QAAQ;AAC3B,QAAM,IAAI,KAAK,IAAI,YAAE,IAAI,KAAK,IAAI,OAAE;AACpC,QAAM,IAAI,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,OAAE,IAAI,KAAK,IAAI,YAAE;AACjF,UAAS,KAAK,MAAM,GAAG,CAAC,IAAI,MAAO,OAAO;AAC5C;AAGO,SAAS,iBAAiB,GAAsB,GAAsB,GAA8B;AACzG,QAAM,IAAI,KAAK,KAAK,EAAE,CAAC,KAAK,KAAK,GAAG;AACpC,QAAM,MAAM,EAAE,CAAC,KAAK,KAAK,GAAG,KAAK,EAAE,CAAC,KAAK;AACzC,QAAM,MAAM,EAAE,CAAC,KAAK,KAAK,GAAG,KAAK,EAAE,CAAC,KAAK;AACzC,QAAM,MAAM,EAAE,CAAC,KAAK,KAAK,GAAG,KAAK,EAAE,CAAC,KAAK;AACzC,QAAM,KAAK,KAAK,IAAI,KAAK,KAAK;AAC9B,QAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,QAAM,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,IAAI,CAAC;AAC5F,QAAM,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK;AAChD,SAAO,KAAK,KAAK,KAAK;AACxB;;;AC5CO,IAAM,iBAAmE;AAAA,EAC9E,yBAAyB,EAAE,WAAW,KAAK;AAC7C;;;ACVA,SAAS,iBAAiB,YAAY,uBAAuB;AAItD,IAAM,kBAAkB;AASxB,IAAM,eAAN,cAA2B,WAAW;AAAA,EAC3C,YAAY,QAAgB,SAAiB,MAAe,mBAA4B;AACtF,UAAM,QAAQ,SAAS,MAAM,iBAAiB;AAC9C,SAAK,OAAO;AAAA,EACd;AACF;AAqBA,eAAsB,aAAa,MAAqD;AACtF,MAAI,CAAC,KAAK,IAAK,OAAM,IAAI,aAAa,KAAK,0BAA0B;AACrE,MAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,aAAa,KAAK,8BAA8B;AAC5E,QAAM,QAAQ,KAAK,WAAW,iBAAiB,QAAQ,QAAQ,EAAE;AACjE,QAAM,MAAM,GAAG,IAAI,cAAc,mBAAmB,KAAK,MAAM,CAAC,aAAa,IAAI,gBAAgB,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;AAEnH,QAAM,YAAY,KAAK,SAAS,WAAW,MAAM,KAAK,UAAU;AAChE,QAAM,MAAM,MAAM,UAAU,KAAK,EAAE,QAAQ,KAAK,QAAQ,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;AAEjG,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,WAAW,YAAY,IAAI,MAAM;AACvC,QAAIA;AACJ,QAAI;AACF,MAAAA,QAAQ,MAAM,IAAI,KAAK;AAAA,IACzB,QAAQ;AACN,MAAAA,QAAO;AAAA,IACT;AACA,UAAM,SAAS,OAAOA,OAAM,UAAU,WAAWA,MAAK,QAAQ;AAC9D,UAAM,OAAO,OAAOA,OAAM,SAAS,WAAWA,MAAK,OAAO;AAC1D,UAAM,aAAa,gBAAgB,IAAI,SAAS,IAAI,aAAa,KAAK,IAAI,KAAK;AAC/E,UAAM,IAAI,aAAa,IAAI,QAAQ,SAAS,GAAG,MAAM,KAAK,QAAQ,MAAM,UAAU,MAAM,UAAU;AAAA,EACpG;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB,QAAQ;AACN,UAAM,IAAI,aAAa,IAAI,QAAQ,kDAAkD,iBAAiB;AAAA,EACxG;AAGA,QAAM,WAAW;AACjB,QAAM,OAAO,YAAY,OAAO,aAAa,WAAW,SAAS,OAAO;AACxE,QAAM,OAAO,OAAO,EAAE,GAAG,MAAM,SAAS,UAAU,MAAM,aAAa,IAAI;AACzE,MAAI,CAAC,kBAAkB,IAAI,GAAG;AAC5B,UAAM,MAAM,QAAQ,YAAY,OAAO,OAAO,KAAK,MAAM,IAAI;AAC7D,UAAM,IAAI,aAAa,IAAI,QAAQ,0BAA0B,GAAG,uBAAuB,eAAe,IAAI,iBAAiB;AAAA,EAC7H;AACA,SAAO,EAAE,QAAQ,KAAK,QAAQ,SAAS,KAAK,SAAS,iBAAiB,KAAK,iBAAiB,SAAS,KAAK,SAAS,OAAO,KAAK,MAAM;AACvI;AAEA,SAAS,kBAAkB,MAAwC;AACjE,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,EAAG,QAAO;AAC7E,QAAM,MAAM;AACZ,SAAO,IAAI,WAAW,mBAAmB,MAAM,QAAQ,IAAI,KAAK,KAAK,OAAO,IAAI,YAAY,YACvF,OAAO,IAAI,YAAY,YAAY,OAAO,IAAI,oBAAoB;AACzE;;;ACrFA,SAAS,iBAAsC;AAC/C,SAAS,uBAAkD;AAO3D,IAAM,UAAU,CAAC,UACd,MAAM,QAAQ,KAAK,IAAI,QAAS,MAA0B;AAuBtD,IAAM,cAAoD;AAAA,EAC/D,WAAW,CAAC,IAAI,IAAI,KAAK,GAAG;AAAA,EAC5B,SAAS,CAAC,IAAI,IAAI,KAAK,GAAG;AAAA,EAC1B,YAAY,CAAC,IAAI,IAAI,IAAI,GAAG;AAAA,EAC5B,YAAY,CAAC,IAAI,IAAI,IAAI,GAAG;AAAA,EAC5B,WAAW,CAAC,KAAK,IAAI,IAAI,GAAG;AAAA,EAC5B,SAAS,CAAC,KAAK,IAAI,IAAI,GAAG;AAAA,EAC1B,SAAS,CAAC,KAAK,IAAI,IAAI,GAAG;AAAA,EAC1B,SAAS,CAAC,KAAK,IAAI,IAAI,GAAG;AAAA,EAC1B,UAAU,CAAC,KAAK,KAAK,IAAI,GAAG;AAAA,EAC5B,cAAc,CAAC,IAAI,KAAK,KAAK,GAAG;AAAA,EAChC,UAAU,CAAC,GAAG,KAAK,IAAI,GAAG;AAAA,EAC1B,OAAO,CAAC,IAAI,IAAI,IAAI,GAAG;AAAA,EACvB,SAAS,CAAC,IAAI,IAAI,IAAI,GAAG;AAC3B;AA4BO,SAAS,gBAAgB,OAAmB,OAA+B,CAAC,GAAsB;AACvG,QAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAM,SAAS,EAAE,GAAG,aAAa,GAAG,KAAK,OAAO;AAChD,QAAM,QAAgC;AAAA,IACpC,IAAI,KAAK,MAAM;AAAA,IACf,MAAM,QAAQ,KAAK;AAAA,IACnB,gBAAgB;AAAA,IAChB,SAAS,CAAC,SAAS,KAAK,MAAM,IAAI,CAAC,MAAM,OAAO,GAAG,YAAY,CAAC;AAAA,IAChE,UAAU,CAAC,SAAS,OAAO,KAAK,SAAS,KAAK,OAAO,WAAW,YAAY;AAAA,IAC5E,UAAU,KAAK,SAAS;AAAA,IACxB,YAAY,KAAK,cAAc;AAAA,IAC/B,gBAAgB;AAAA;AAAA,IAEhB,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU,KAAK,YAAY;AAAA,IAC3B,gBAAgB;AAAA,MACd,SAAS,CAAC,YAAY;AAAA,MACtB,UAAU,CAAC,KAAK,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO,IAAI,UAAkB,KAAK,WAAW,EAAE,GAAG,OAAO,UAAU,KAAK,SAAS,IAA8B,KAAK;AACtH;AAoBA,SAAS,cAAc,MAAc,GAAoB;AACvD,QAAM,OAAO,KAAK,MAAM,UAAU,IAAI,KAAK,QAAQ,KAAK;AACxD,MAAI,OAAO;AACX,MAAI,KAAK,QAAQ,KAAK,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;AACnD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,IAAI,CAAC;AACpB,UAAM,IAAI,KAAK,CAAC;AAChB,UAAM,IAAI,iBAAiB,GAAG,GAAG,CAAC;AAClC,QAAI,IAAI,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI;AAChD,aAAO;AACP,WAAK,QAAQ,GAAG,CAAC;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,OAAmB,eAAe,GAAwB;AAC3F,QAAM,MAA2B,CAAC;AAClC,aAAW,QAAQ,QAAQ,KAAK,GAAG;AACjC,UAAM,MAAM,CAAC,MAAqB,WAChC,OAAO;AAAA,MAAQ,CAAC,GAAG,UACjB,IAAI,KAAK;AAAA,QACP,IAAI,GAAG,KAAK,EAAE,IAAI,IAAI,IAAI,KAAK;AAAA,QAC/B,QAAQ,KAAK;AAAA,QACb,WAAW,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,QACA,UAAU,OAAO,GAAG,YAAY;AAAA,QAChC,SAAS,cAAc,MAAM,CAAC;AAAA,MAChC,CAAC;AAAA,IACH;AACF,QAAI,WAAW,KAAK,QAAQ;AAC5B,QAAI,SAAS,KAAK,MAAM;AAAA,EAC1B;AACA,SAAO;AACT;AAoBA,IAAM,QAAkC,CAAC,SAAS,SAAS;AASpD,SAAS,gBAAgB,OAAmB,MAAoE;AACrH,QAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,SAAS,KAAK,MAAM;AAC1B,QAAM,MAAM,mBAAmB,OAAO,YAAY;AAClD,QAAM,SAA+C,CAAC;AACtD,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,KAAK,OAAO,IAAI;AAC5B,QAAI,CAAC,IAAK;AACV,UAAM,QAAiD;AAAA,MACrD,IAAI,GAAG,MAAM,IAAI,IAAI;AAAA,MACrB,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,MACvC,YAAY;AAAA,MACZ,aAAa,CAAC,MAAM,EAAE;AAAA,MACtB,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,UAAU,WAAW,EAAE;AAAA,MACrD,WAAW,KAAK,aAAa;AAAA,MAC7B,WAAW;AAAA,MACX,UAAU,KAAK,YAAY;AAAA,MAC3B,gBAAgB,EAAE,gBAAgB,CAAC,SAAS,EAAE;AAAA,IAChD;AACA,WAAO;AAAA,MACL,IAAI;AAAA,QACF,KAAK,WAAY,EAAE,GAAG,OAAO,UAAU,KAAK,SAAS,IAAgD;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;;;ACrNA,SAAS,uBAAkD;AAmB3D,IAAM,SAAS,oBAAI,QAAgB;AAOnC,SAAS,YAAY,KAA0C;AAC7D,QAAM,KAAK,IAAI,UAAU,EAAE,WAAW,QAAQ;AAC9C,SAAO,IAAI,qBAAqB,GAAG;AACrC;AAaO,SAAS,kBAAkB,KAAqB,OAA2B,CAAC,GAAgB;AACjG,MAAI,YAAY,GAAG,MAAM,SAAS,CAAC,OAAO,IAAI,GAAG,GAAG;AAClD,WAAO,IAAI,GAAG;AACd,YAAQ;AAAA,MACN;AAAA,IAGF;AAAA,EACF;AACA,QAAM,UAAU,IAAI,gBAAgB,EAAE,GAAG,MAAM,aAAa,KAAK,CAAC;AAClE,MAAI,WAAW,OAAO;AACtB,MAAI,UAAU;AACd,SAAO;AAAA,IACL;AAAA,IACA,UAAU,QAAQ;AAChB,cAAQ,SAAS,EAAE,OAAO,CAAC;AAAA,IAC7B;AAAA,IACA,SAAS;AACP,UAAI,QAAS;AACb,gBAAU;AACV,UAAI,cAAc,OAAO;AAAA,IAC3B;AAAA,EACF;AACF;;;ACtCA,SAAS,cAAAC,mBAAkB;","names":["body","UnmapError"]}
|
|
1
|
+
{"version":3,"sources":["../src/geometry.ts","../src/options.ts","../src/fetch.ts","../src/layers.ts","../src/overlay.ts","../src/index.ts"],"sourcesContent":["import type { LngLatZ } from \"./types\";\n\n/**\n * The height to draw a baked point at, on a map whose terrain has this vertical exaggeration.\n *\n * MapLibre draws terrain at `DEM height × exaggeration`, measured from sea level (no offset), and\n * deck.gl layers are not draped on that terrain: they sit at whatever z they are given. A baked z\n * therefore has to be scaled by the same factor to stay on the terrain the map draws. At the\n * default exaggeration of 1 the baked z is returned as is.\n *\n * The whole height is scaled, including the part that is above the ground (a tower, the cable's\n * clearance), because the lifts document carries one z per point, not ground plus offset. At 1.5×\n * a 12 m tower draws 18 m tall: still on the ground at its foot, just taller. Read the map's own\n * value with `map.getTerrain()?.exaggeration ?? 1`.\n */\nexport function bakedZ(point: LngLatZ, exaggeration = 1): number {\n if (!(Number.isFinite(exaggeration) && exaggeration > 0)) {\n throw new RangeError(`exaggeration must be a positive number, got ${exaggeration}`);\n }\n return (point[2] ?? 0) * exaggeration;\n}\n\n/** `point` with its z scaled by `exaggeration`; lng and lat untouched. */\nexport function scaled(point: LngLatZ, exaggeration: number): LngLatZ {\n return [point[0], point[1], bakedZ(point, exaggeration)];\n}\n\nconst RAD = Math.PI / 180;\n\n/** Initial great-circle bearing from `a` to `b`, degrees clockwise from north, in [0, 360). */\nexport function bearing(a: readonly number[], b: readonly number[]): number {\n const [lng1 = 0, lat1 = 0] = a;\n const [lng2 = 0, lat2 = 0] = b;\n const φ1 = lat1 * RAD;\n const φ2 = lat2 * RAD;\n const Δλ = (lng2 - lng1) * RAD;\n const y = Math.sin(Δλ) * Math.cos(φ2);\n const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ);\n return ((Math.atan2(y, x) / RAD) + 360) % 360;\n}\n\n/** Squared planar distance from `p` to segment `a`–`b`, in degrees with longitude scaled by cos(lat). */\nexport function segmentDistance2(p: readonly number[], a: readonly number[], b: readonly number[]): number {\n const k = Math.cos((p[1] ?? 0) * RAD);\n const px = (p[0] ?? 0) * k, py = p[1] ?? 0;\n const ax = (a[0] ?? 0) * k, ay = a[1] ?? 0;\n const bx = (b[0] ?? 0) * k, by = b[1] ?? 0;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / len2));\n const cx = ax + t * dx - px, cy = ay + t * dy - py;\n return cx * cx + cy * cy;\n}\n","/**\n * MapLibre options `@unmap/deck` needs at construction time. Pass them as `createMap`'s\n * `maplibre` option (or spread them into `new maplibregl.Map({...})`).\n *\n * MapLibre creates its WebGL context with `antialias: false`, which gives deck.gl's lift cables\n * hard, stair-stepped edges. Antialiasing is a context attribute, so it can only be chosen when\n * the map is created; `createDeckOverlay` cannot turn it on later and warns instead.\n */\nexport const deckMapOptions: { canvasContextAttributes: { antialias: true } } = {\n canvasContextAttributes: { antialias: true },\n};\n","import { DEFAULT_GATEWAY, UnmapError, parseRetryAfter } from \"@unmap/core\";\nimport type { Lifts3dDocument } from \"./types\";\n\n/** The only document schema this package reads. */\nexport const LIFTS_3D_SCHEMA = \"unmap.ski-lifts-3d.v1\";\n\n/**\n * A lifts-3D failure: a non-2xx answer from the gateway (`status` and `code` from it, such as\n * `403 addon_required` for a key without the ski add-on), or a body that is not a\n * `unmap.ski-lifts-3d.v1` document (`code: \"schema_mismatch\"`).\n *\n * Extends `UnmapError`, so one `instanceof UnmapError` catches it with every other unmap error.\n */\nexport class Lifts3dError extends UnmapError {\n constructor(status: number, message: string, code?: string, retryAfterSeconds?: number) {\n super(status, message, code, retryAfterSeconds);\n this.name = \"Lifts3dError\";\n }\n}\n\nexport interface FetchLifts3dOptions {\n /** An unmap key with the `ski` add-on. It is sent to `gateway` and nowhere else. */\n key: string;\n /** A ski area id from `/ski/areas`, such as `osm-way-123`. */\n areaId: string;\n /** Gateway origin; defaults to `https://api.unmap.dev`. */\n gateway?: string;\n /** A `fetch` to use instead of the global one. */\n fetch?: typeof fetch;\n signal?: AbortSignal;\n}\n\n/**\n * Fetch an area's baked 3D lifts (`GET /ski/areas/{id}/lifts-3d`).\n *\n * The data sits behind the `ski` add-on; the renderers in this package do not. The document's z\n * values are metres above sea level from `terrain_release`, ready for `liftCablesLayer` and\n * `liftModelsLayer`.\n */\nexport async function fetchLifts3d(opts: FetchLifts3dOptions): Promise<Lifts3dDocument> {\n if (!opts.key) throw new Lifts3dError(400, \"fetchLifts3d needs a key\");\n if (!opts.areaId) throw new Lifts3dError(400, \"fetchLifts3d needs an areaId\");\n const base = (opts.gateway ?? DEFAULT_GATEWAY).replace(/\\/+$/, \"\");\n const url = `${base}/ski/areas/${encodeURIComponent(opts.areaId)}/lifts-3d?${new URLSearchParams({ key: opts.key })}`;\n // Bound to globalThis: a bare `fetch` called with another receiver is rejected by browsers.\n const fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n const res = await fetchImpl(url, { signal: opts.signal, headers: { accept: \"application/json\" } });\n\n if (!res.ok) {\n const fallback = `lifts-3d ${res.status}`;\n let body: { error?: unknown; code?: unknown } | undefined;\n try {\n body = (await res.json()) as { error?: unknown; code?: unknown };\n } catch {\n body = undefined;\n }\n const reason = typeof body?.error === \"string\" ? body.error : undefined;\n const code = typeof body?.code === \"string\" ? body.code : undefined;\n const retryAfter = parseRetryAfter(res.headers?.get(\"retry-after\") ?? null) ?? undefined;\n throw new Lifts3dError(res.status, reason ? `${reason} (${fallback})` : fallback, code, retryAfter);\n }\n\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Lifts3dError(res.status, \"lifts-3d answered with a body that is not JSON\", \"schema_mismatch\");\n }\n // The gateway answers with the ski routes' `{ data, meta }` envelope; the release is meta's\n // data_version. The document callers get back is flat.\n const envelope = body as { data?: Record<string, unknown>; meta?: { data_version?: unknown } } | null;\n const data = envelope && typeof envelope === \"object\" ? envelope.data : undefined;\n const flat = data ? { ...data, release: envelope?.meta?.data_version } : undefined;\n if (!isLifts3dDocument(flat)) {\n const got = data && \"schema\" in data ? String(data.schema) : \"no schema\";\n throw new Lifts3dError(res.status, `lifts-3d answered with ${got}; this client reads ${LIFTS_3D_SCHEMA}`, \"schema_mismatch\");\n }\n return { schema: flat.schema, release: flat.release, terrain_release: flat.terrain_release, area_id: flat.area_id, lifts: flat.lifts };\n}\n\nfunction isLifts3dDocument(body: unknown): body is Lifts3dDocument {\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) return false;\n const doc = body as Record<string, unknown>;\n return doc.schema === LIFTS_3D_SCHEMA && Array.isArray(doc.lifts) && typeof doc.release === \"string\"\n && typeof doc.area_id === \"string\" && typeof doc.terrain_release === \"string\";\n}\n","import { PathLayer, type PathLayerProps } from \"@deck.gl/layers\";\nimport { ScenegraphLayer, type ScenegraphLayerProps } from \"@deck.gl/mesh-layers\";\nimport { bearing, scaled, segmentDistance2 } from \"./geometry\";\nimport type { Lift3d, Lifts3dDocument, LngLatZ, RGBA } from \"./types\";\n\n/** A lifts document, or just its `lifts`. */\nexport type LiftsInput = Lifts3dDocument | readonly Lift3d[];\n\nconst liftsOf = (input: LiftsInput): Lift3d[] =>\n (Array.isArray(input) ? input : (input as Lifts3dDocument).lifts) as Lift3d[];\n\n/** Known OSM `aerialway=*` values, plus `default` for anything else. */\nexport type LiftColorKey =\n | \"cable_car\"\n | \"gondola\"\n | \"mixed_lift\"\n | \"chair_lift\"\n | \"drag_lift\"\n | \"t-bar\"\n | \"j-bar\"\n | \"platter\"\n | \"rope_tow\"\n | \"magic_carpet\"\n | \"zip_line\"\n | \"goods\"\n | \"default\";\n\n/**\n * Cable colour by aerialway. Dark, cool and unsaturated so a cable reads as steel against the\n * winter style's snow; enclosed cabins (gondola, cable car) in blue, surface lifts in brown.\n * Magenta is the interface accent and stays out.\n */\nexport const LIFT_COLORS: Readonly<Record<LiftColorKey, RGBA>> = {\n cable_car: [13, 71, 161, 255],\n gondola: [30, 96, 180, 255],\n mixed_lift: [55, 71, 79, 255],\n chair_lift: [38, 50, 56, 255],\n drag_lift: [109, 76, 65, 255],\n \"t-bar\": [109, 76, 65, 255],\n \"j-bar\": [109, 76, 65, 255],\n platter: [109, 76, 65, 255],\n rope_tow: [141, 110, 99, 255],\n magic_carpet: [96, 125, 139, 255],\n zip_line: [0, 105, 92, 255],\n goods: [97, 97, 97, 255],\n default: [66, 66, 66, 255],\n};\n\nexport interface LiftCablesLayerOptions {\n /** Layer id. Defaults to `unmap-lift-cables`; keep it stable so deck.gl diffs instead of rebuilding. */\n id?: string;\n /**\n * The map's terrain exaggeration (`map.getTerrain()?.exaggeration ?? 1`). Every baked z is\n * multiplied by it, from sea level, as MapLibre multiplies the DEM; see `bakedZ`. Default 1.\n */\n exaggeration?: number;\n /** Cable width in `widthUnits`. Default 2. */\n width?: number;\n /** `pixels` (the default) keeps cables legible at every zoom; `meters` makes them real-sized. */\n widthUnits?: \"pixels\" | \"meters\" | \"common\";\n /** Colours per aerialway, merged over `LIFT_COLORS`. */\n colors?: Partial<Record<string, RGBA>>;\n /** Pick lifts on hover and click. Default false. */\n pickable?: boolean;\n /** MapLibre layer id to draw beneath (interleaved mode), e.g. the first label layer. */\n beforeId?: string;\n}\n\n/**\n * A deck.gl `PathLayer` drawing each lift's `cable` in 3D at its baked height.\n *\n * Heights are baked by the pipeline and never queried at render time: deck.gl layers do not drape\n * on MapLibre terrain, so the z in the file is the only thing that puts a cable on the mountain.\n */\nexport function liftCablesLayer(input: LiftsInput, opts: LiftCablesLayerOptions = {}): PathLayer<Lift3d> {\n const exaggeration = opts.exaggeration ?? 1;\n const colors = { ...LIFT_COLORS, ...opts.colors } as Record<string, RGBA | undefined>;\n const props: PathLayerProps<Lift3d> = {\n id: opts.id ?? \"unmap-lift-cables\",\n data: liftsOf(input),\n positionFormat: \"XYZ\",\n getPath: (lift) => lift.cable.map((p) => scaled(p, exaggeration)),\n getColor: (lift) => colors[lift.aerialway] ?? colors.default ?? LIFT_COLORS.default,\n getWidth: opts.width ?? 2,\n widthUnits: opts.widthUnits ?? \"pixels\",\n widthMinPixels: 1,\n // Cables are seen from every pitch; billboarding keeps a thin line from vanishing edge-on.\n billboard: true,\n capRounded: true,\n jointRounded: true,\n pickable: opts.pickable ?? false,\n updateTriggers: {\n getPath: [exaggeration],\n getColor: [JSON.stringify(opts.colors ?? {})],\n },\n };\n // `beforeId` is read by @deck.gl/maplibre in interleaved mode, not declared on PathLayerProps.\n return new PathLayer<Lift3d>(opts.beforeId ? { ...props, beforeId: opts.beforeId } as PathLayerProps<Lift3d> : props);\n}\n\n/** What a model stands for. `station` is both terminals; `pylon` is every tower. */\nexport type LiftModelKind = \"pylon\" | \"station\";\n\n/** One placed model: a station or a pylon of one lift. */\nexport interface LiftModelInstance {\n /** `<liftId>:<kind>:<index>`, stable across releases while OSM ids are. */\n id: string;\n liftId: string;\n aerialway: string;\n kind: LiftModelKind;\n index: number;\n /** Baked position with z already scaled by the exaggeration. */\n position: LngLatZ;\n /** Direction of the line at this point, degrees clockwise from north. */\n bearing: number;\n}\n\n/** The bearing of the cable segment nearest to `p`, or of the station line if there is no cable. */\nfunction lineBearingAt(lift: Lift3d, p: LngLatZ): number {\n const line = lift.cable.length >= 2 ? lift.cable : lift.stations;\n let best = Infinity;\n let at = bearing(lift.stations[0], lift.stations[1]);\n for (let i = 1; i < line.length; i++) {\n const a = line[i - 1]!;\n const b = line[i]!;\n const d = segmentDistance2(p, a, b);\n if (d < best && (a[0] !== b[0] || a[1] !== b[1])) {\n best = d;\n at = bearing(a, b);\n }\n }\n return at;\n}\n\n/**\n * Every station and pylon as a model instance, oriented along its lift. Exposed so a caller can\n * build their own layer (or a label layer) over the same points `liftModelsLayer` draws.\n */\nexport function liftModelInstances(input: LiftsInput, exaggeration = 1): LiftModelInstance[] {\n const out: LiftModelInstance[] = [];\n for (const lift of liftsOf(input)) {\n const add = (kind: LiftModelKind, points: readonly LngLatZ[]) =>\n points.forEach((p, index) =>\n out.push({\n id: `${lift.id}:${kind}:${index}`,\n liftId: lift.id,\n aerialway: lift.aerialway,\n kind,\n index,\n position: scaled(p, exaggeration),\n bearing: lineBearingAt(lift, p),\n }),\n );\n add(\"station\", lift.stations);\n add(\"pylon\", lift.pylons);\n }\n return out;\n}\n\nexport interface LiftModelsLayerOptions {\n /**\n * glTF/GLB URL per kind. Supplied by the caller; this package bundles no models. A kind with no\n * URL is not drawn.\n */\n models: Partial<Record<LiftModelKind, string>>;\n /** Id prefix; each layer is `<id>-<kind>`. Defaults to `unmap-lift-models`. */\n id?: string;\n /** The map's terrain exaggeration, as for `liftCablesLayer`. Default 1. */\n exaggeration?: number;\n /** Model units to metres. Default 1 (models authored in metres). */\n sizeScale?: number;\n /** Extra yaw in degrees, for a model authored facing another way. Default 0. */\n yawOffset?: number;\n pickable?: boolean;\n beforeId?: string;\n}\n\nconst KINDS: readonly LiftModelKind[] = [\"pylon\", \"station\"];\n\n/**\n * deck.gl `ScenegraphLayer`s placing a model at each pylon and station, one layer per kind that\n * has a URL in `models` (a ScenegraphLayer draws one scenegraph).\n *\n * The model origin goes at the baked point. Models are glTF (Y up), so they are rolled 90° onto\n * deck.gl's Z up, and yawed by `-bearing` so the model's forward axis runs up the line.\n */\nexport function liftModelsLayer(input: LiftsInput, opts: LiftModelsLayerOptions): ScenegraphLayer<LiftModelInstance>[] {\n const exaggeration = opts.exaggeration ?? 1;\n const yawOffset = opts.yawOffset ?? 0;\n const prefix = opts.id ?? \"unmap-lift-models\";\n const all = liftModelInstances(input, exaggeration);\n const layers: ScenegraphLayer<LiftModelInstance>[] = [];\n for (const kind of KINDS) {\n const url = opts.models[kind];\n if (!url) continue;\n const props: ScenegraphLayerProps<LiftModelInstance> = {\n id: `${prefix}-${kind}`,\n data: all.filter((i) => i.kind === kind),\n scenegraph: url,\n getPosition: (i) => i.position,\n getOrientation: (i) => [0, -i.bearing + yawOffset, 90],\n sizeScale: opts.sizeScale ?? 1,\n _lighting: \"pbr\",\n pickable: opts.pickable ?? false,\n updateTriggers: { getOrientation: [yawOffset] },\n };\n layers.push(\n new ScenegraphLayer<LiftModelInstance>(\n opts.beforeId ? ({ ...props, beforeId: opts.beforeId } as ScenegraphLayerProps<LiftModelInstance>) : props,\n ),\n );\n }\n return layers;\n}\n","import { MapLibreOverlay, type MapLibreOverlayProps } from \"@deck.gl/maplibre\";\nimport type { LayersList } from \"@deck.gl/core\";\nimport type { Map as MaplibreMap } from \"maplibre-gl\";\n\n/** The map `createDeckOverlay` takes: a MapLibre `Map`, such as `createMap` returns. */\nexport type DeckOverlayMap = MaplibreMap;\n\n/** Overlay props, less `interleaved`: this package always shares MapLibre's WebGL context. */\nexport type DeckOverlayOptions = Omit<MapLibreOverlayProps, \"interleaved\">;\n\nexport interface DeckOverlay {\n /** The underlying `MapLibreOverlay`, for picking (`pickObject`) or any other deck.gl prop. */\n readonly overlay: MapLibreOverlay;\n /** Replace the drawn layers. Keep layer ids stable so deck.gl diffs rather than rebuilds. */\n setLayers(layers: LayersList): void;\n /** Take the overlay off the map and release its GPU resources. Safe to call twice. */\n remove(): void;\n}\n\nconst warned = new WeakSet<object>();\n\n/**\n * Whether the map's WebGL context was created with antialiasing. `undefined` when it cannot be\n * told (no WebGL2 context yet). Reads the context the map already made: `getContext` with the\n * same type returns the existing one and never creates a second.\n */\nfunction antialiased(map: DeckOverlayMap): boolean | undefined {\n const gl = map.getCanvas().getContext(\"webgl2\");\n return gl?.getContextAttributes()?.antialias;\n}\n\n/**\n * Add a deck.gl overlay to a MapLibre map, interleaved: deck.gl draws into MapLibre's own WebGL\n * context and layer stack (one context, depth shared with the terrain), never a second canvas.\n *\n * Create the map with `deckMapOptions` for smooth cables; antialiasing cannot be switched on after\n * the map exists, so this warns once per map when it is off.\n *\n * const deck = createDeckOverlay(map, { layers: [liftCablesLayer(lifts)] });\n * deck.setLayers([...]);\n * deck.remove();\n */\nexport function createDeckOverlay(map: DeckOverlayMap, opts: DeckOverlayOptions = {}): DeckOverlay {\n if (antialiased(map) === false && !warned.has(map)) {\n warned.add(map);\n console.warn(\n \"@unmap/deck: this map was created without antialiasing, so deck.gl lines will draw with hard \" +\n \"edges. Create it with `maplibre: deckMapOptions` (createMap) or spread `deckMapOptions` into \" +\n \"the MapLibre Map options.\",\n );\n }\n const overlay = new MapLibreOverlay({ ...opts, interleaved: true });\n map.addControl(overlay);\n let removed = false;\n let layers: LayersList = opts.layers ?? [];\n // @deck.gl/maplibre adds interleaved layers to the map only while `map.isStyleLoaded()`, which is\n // false while any tile is still loading, and retries only on `styledata`. Layers set during a\n // camera flight would otherwise never be drawn, so they are applied again once the map is idle.\n const reapplyWhenIdle = () => {\n if (removed || map.isStyleLoaded()) return;\n map.once(\"idle\", () => {\n if (!removed) overlay.setProps({ layers });\n });\n };\n reapplyWhenIdle();\n return {\n overlay,\n setLayers(next) {\n layers = next;\n overlay.setProps({ layers });\n reapplyWhenIdle();\n },\n remove() {\n if (removed) return;\n removed = true;\n map.removeControl(overlay);\n },\n };\n}\n","/**\n * @unmap/deck: deck.gl layers for unmap maps, interleaved in MapLibre's WebGL context.\n *\n * Optional and separate from @unmap/maps, so a plain map never loads deck.gl. `fetchLifts3d`,\n * `bakedZ` and `deckMapOptions` import no renderer, and the package is `sideEffects: false`, so a\n * bundler drops deck.gl from a chunk that uses only them; load the layers with a dynamic\n * `import(\"@unmap/deck\")` when the user turns 3D on.\n */\nexport type { Lift3d, Lifts3dDocument, LngLatZ, RGBA } from \"./types\";\nexport { bakedZ } from \"./geometry\";\nexport { deckMapOptions } from \"./options\";\nexport { LIFTS_3D_SCHEMA, Lifts3dError, fetchLifts3d, type FetchLifts3dOptions } from \"./fetch\";\nexport {\n LIFT_COLORS,\n liftCablesLayer,\n liftModelInstances,\n liftModelsLayer,\n type LiftCablesLayerOptions,\n type LiftColorKey,\n type LiftModelInstance,\n type LiftModelKind,\n type LiftModelsLayerOptions,\n type LiftsInput,\n} from \"./layers\";\nexport { createDeckOverlay, type DeckOverlay, type DeckOverlayMap, type DeckOverlayOptions } from \"./overlay\";\n\n// Re-exported so `catch (e) { if (e instanceof UnmapError) }` works without adding @unmap/core.\nexport { UnmapError } from \"@unmap/core\";\n"],"mappings":"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","names":["body","UnmapError"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unmap/deck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "deck.gl layers for unmap maps: 3D ski lifts on MapLibre terrain, interleaved in one WebGL context",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@unmap/core": "0.
|
|
41
|
+
"@unmap/core": "0.25.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@deck.gl/core": "~9.4.0",
|