@nika-js/onlymap 0.6.20 → 0.6.22
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/CHANGELOG.md +19 -0
- package/README.md +2 -2
- package/dist/{LercDecode.es-DiDn51b8.js → LercDecode.es-Cm-Ah1Pr.js} +1 -1
- package/dist/actions.d.ts +94 -1
- package/dist/attribute-resolution.d.ts +55 -1
- package/dist/{basemap-Bvtudw-w.js → basemap-BCZ-MbEU.js} +2 -2
- package/dist/declarative-filter.d.ts +2 -16
- package/dist/effect-track.d.ts +94 -0
- package/dist/effects.d.ts +2 -0
- package/dist/elements/om-map.d.ts +9 -8
- package/dist/elements/om-story.d.ts +18 -0
- package/dist/{geoparquet-DFfq6-JJ.js → geoparquet-BaYtod1j.js} +1 -1
- package/dist/html-data.d.ts +14 -0
- package/dist/{index-DIHnIeho.js → index-BlUSpugF.js} +1 -1
- package/dist/{index-Cq0qmoDj.js → index-C2DPJtsQ.js} +2 -2
- package/dist/{index-CPthQWzC.js → index-Ddn4yvyL.js} +14997 -14636
- package/dist/{index-ZDGLuUoq.js → index-GkhsIJWB.js} +1 -1
- package/dist/{index-AlG5NjjQ.js → index-Qza7MX_l.js} +1 -1
- package/dist/internal-ids.d.ts +2 -0
- package/dist/ir-snapshot.d.ts +2 -0
- package/dist/ir.d.ts +8 -0
- package/dist/{lerc-C3kqqJ1B.js → lerc-Dt2MXtZG.js} +2 -2
- package/dist/onlymap.standalone.js +24234 -23873
- package/dist/onlymapjs.js +1 -1
- package/dist/parse-manifest.d.ts +8 -0
- package/dist/programmatic.d.ts +3 -2
- package/dist/{raster-6tndfpHv.js → raster-DBB0kjvs.js} +2 -2
- package/dist/{raster-pipeline-DVLch-nI.js → raster-pipeline-C9FDdaMd.js} +1 -1
- package/dist/react.js +18 -17
- package/dist/runtime-core.d.ts +34 -0
- package/dist/snapshot.d.ts +15 -0
- package/dist/version.d.ts +1 -1
- package/dist/{zarr-D5UCDgG7.js → zarr-9LzdL7Zm.js} +2 -2
- package/docs/stories.md +2 -0
- package/llms.txt +3 -2
- package/onlymapjs.attributes.json +1582 -0
- package/onlymapjs.html-data.json +282 -278
- package/package.json +2 -1
- package/skills/onlymapjs/SKILL.md +1 -1
- package/skills/onlymapjs/references/syntax.md +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,25 @@ Note: npm collapsed a few closely-spaced releases — the GPX/FlatGeobuf (0.5.4)
|
|
|
8
8
|
and GeoParquet (0.5.5) work shipped to npm together as **0.5.6**, so npm's
|
|
9
9
|
version list jumps 0.5.3 → 0.5.6. Each logical version is listed here regardless.
|
|
10
10
|
|
|
11
|
+
## 0.6.22 — 2026-08-26
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Scale-dependent visibility on every layer type.** `visible-zoom-range="[8, 14]"` hides a layer outside that zoom span (min inclusive, max exclusive — the standard minzoom/maxzoom convention), the everyday GIS pattern for keeping dense layers from swamping a zoomed-out view. Works on vector layers, not just tile layers; the layer stays in the legend and layer switcher while zoom-hidden. (#38)
|
|
15
|
+
- **A machine-readable attribute contract, `onlymapjs.attributes.json`.** Tools that generate OnlyMapJS markup can now validate attributes per layer type — the editor IntelliSense file is a flat union and could pass attributes the runtime rejects. The new file is generated from the same registry the runtime validates against, so the two can't drift; IntelliSense hovers now also say which layer types accept each attribute. (#38)
|
|
16
|
+
- **A silent-empty-layer class of mistake now warns.** A layer whose required position accessor resolves to nothing for every row — a `TextLayer` fed GeoJSON with no `get-position` being the reported case — previously rendered an empty map with a clean console. It now warns once with the exact fix, on the console and through the `validate` panel. Layers where the default genuinely works are untouched. (#39)
|
|
17
|
+
|
|
18
|
+
## 0.6.21 — 2026-08-26
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **Recordings now capture animations, not just end states.** Fade, pulse, trace, and populate steps animate frame-accurately in `onlymapjs record` output and paced story runs — a 2-second border trace draws itself on across 2 seconds of video instead of appearing fully drawn. Seeking a story under the recording switch lands mid-animation too (a half-drawn trace is just a scene), which external frame renderers rely on. One documented limit: the `trace follow` camera is skipped during recorded runs, since the paced route drives the camera.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **On-map labels (`anchor="surface"`) now sit on the landmass they belong to.** Ring selection previously favored densely-digitized slivers and could even pick a hole; features without a usable anchor point no longer draw a stray label at null island.
|
|
25
|
+
- **The `trace follow` camera stays glued to the drawing tip.** It previously sampled the path by distance while the ink advanced by timestamps, so routes with dwells or slow legs pulled the camera away from the head; layers with several separately-timed paths no longer make the camera jump between them.
|
|
26
|
+
- **Blob-format snapshots are byte-stable again.** Stability comparison silently never matched for blob output, so exactly the format video renderers request lost its guarantee.
|
|
27
|
+
- **Seeking a story no longer overwrites fit-bounds or zoom-to poses between camera legs.**
|
|
28
|
+
- **Paid-license render exemption is scoped to real local browser pages** — it no longer applies in environments without a page location at all.
|
|
29
|
+
|
|
11
30
|
## 0.6.20 — 2026-08-26
|
|
12
31
|
|
|
13
32
|
### Fixed
|
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ A handful of elements, one rule: **attributes are kebab-case versions of deck.gl
|
|
|
83
83
|
| Element | Role |
|
|
84
84
|
|---|---|
|
|
85
85
|
| `<om-map>` | The map. `center`, `zoom`, `pitch`, `bearing`; `basemap` takes a free preset (`positron`, `liberty`, `dark-matter`, `osm`, …), a style URL, or `"none"` (standalone canvas) — and switches **live**; `validate` for a live on-page error panel. Give it a height: a custom element is `display:inline` by default, so the library injects a `display:block` default (fills a sized parent, else a 400px floor) to keep a bare map visible, but set an explicit height (`om-map { height: 100vh }`) for real layout — any height you set wins outright, including one below the floor. A map that still collapses warns in the console; `hidden` and `display:none` maps stay hidden and stay quiet. |
|
|
86
|
-
| `<om-layer>` | Any of **39 layer types** by name — all of deck.gl's core, geo, aggregation, and mesh layers (Scatterplot, GeoJson, Arc, Path, Heatmap, Hexagon, Trips, Tile, Tile3D, Scenegraph, …) plus the built-in `PopupLayer` for WebGL badges/labels at scale, the native `COGLayer` for GeoTIFF rasters, `ZarrLayer` for chunked Zarr/GeoZarr rasters, `ImageOverlay` for georeferenced drone JPEGs, `BIMLayer` for BIM source files (`.ifc` today) loaded straight in the browser with no pre-conversion step, and `Route`/`Tracking` for styled routes and live position tracking. `id` required; `label`/`color` feed the legend. |
|
|
86
|
+
| `<om-layer>` | Any of **39 layer types** by name — all of deck.gl's core, geo, aggregation, and mesh layers (Scatterplot, GeoJson, Arc, Path, Heatmap, Hexagon, Trips, Tile, Tile3D, Scenegraph, …) plus the built-in `PopupLayer` for WebGL badges/labels at scale, the native `COGLayer` for GeoTIFF rasters, `ZarrLayer` for chunked Zarr/GeoZarr rasters, `ImageOverlay` for georeferenced drone JPEGs, `BIMLayer` for BIM source files (`.ifc` today) loaded straight in the browser with no pre-conversion step, and `Route`/`Tracking` for styled routes and live position tracking. `id` required; `label`/`color` feed the legend. `visible-zoom-range="[8, 14]"` gives any layer scale-dependent visibility (hidden outside min ≤ zoom < max, the standard minzoom/maxzoom convention) — the everyday GIS pattern for keeping a dense layer from swamping a zoomed-out view. |
|
|
87
87
|
| `<om-widget>` | UI panels. Built-ins: `legend` (symbology-aware: color scales render as gradient ramps or class ranges, categorical ternaries as discrete palettes), `layer-switcher`, `basemap-switcher`, `lighting`, `clip-box`, `zoom-controls`, `undo-redo`, `scale-bar` (metric/imperial/nautical `units`), `attribution`, `filter`, `draw` (point/line/polygon sketch capture, GeoJSON save/autosave; lines/polygons complete via double-click, touch double-tap — detected by the library itself, since iOS WebViews never synthesize `dblclick` from taps — Enter, or the toolbar's Finish button; `export-3d` adds an "Export 3D" button that clips loaded `Tile3DLayer`/`BIMLayer` content to the drawn footprint and downloads it as a portable GLB — re-framed to a local coordinate frame at the footprint's own centroid, each triangle carrying its own source color as vertex colors, no textures — or, with `export-3d="b3dm"`, the same mesh wrapped for Cesium/3D-Tiles pipelines; only currently-visible 3D Tiles/BIM layers are included — a layer hidden via `visible="false"` or the `toggle-layer` action is skipped, with a distinct console warning for "nothing loaded" vs. "everything hidden"), `measure` (geodesic distance + area + cut/fill volume — live labels, `units` toggle, an `om-measure` readout event; `modes="distance area volume"` adds a footprint-then-extrude tool: outline a polygon, double-click (double-tap on touch) to close it — it turns solid teal, ready — then drag the double-headed arrow gizmo that appears at its centroid up to fill or down to cut, reading out Cut/Fill/Net (signed, fill−cut)/Total (unsigned, cut+fill) volume plus Area/Perimeter, each labelled with its own sign convention. The math is a REAL per-cell grid integration: closing a footprint bulk-loads its covering DEM tiles, lays a metric grid in a local tangent frame at the ring centroid (cell size = the DEM's ground-sample distance; scanline point-in-polygon; bilinear, tile-seam-correct sampling; worker-offloaded), and integrates terrain-vs-base per cell — mixed cut AND fill within one footprint on undulating ground, with a published ±error (per-cell cellArea × 1.5 × GSD, summed per side), the cell size used, and a no-data warning all carried on the `om-measure` readout (`cellSizeM`/`gsdM`/`cutErrorM3`/`fillErrorM3`/`nodataFraction`). A `base-surface` attribute picks the reference surface: `custom` (default — the gizmo's draggable target plane), or boundary-derived stockpile strategies with no gizmo (`triangulated` boundary TIN, `plane` least-squares fit, `lowest`/`highest`/`average`). On `custom`, the extruded prism's own boundary hugs each corner's real ground elevation by default (so it doesn't visibly float above or sink below sloped terrain) — a "Flat target plane" toggle button appears above the readout once a footprint closes, switching that rendering to a single level plane instead (a rendering choice only; the underlying cut/fill numbers were already computed against one flat target elevation either way). Requires `terrain` on `<om-map>` — validation warns if `volume` is in `modes` with none (without terrain a flat-plane fallback runs, with no error figures — nothing honest to quote). A `profile` attribute alongside `modes` — not a mode of its own — samples elevation around a volume footprint's own perimeter as it's drawn and closed, live, and dispatches it on `om-measure`'s `profileSeries` field for a `dynamic-chart` widget to plot. Each sample is `{x: distance-from-start-m, y: elevation-m}`, and samples that ARE one of the drawn footprint's own corners additionally carry `vertexIndex` (0-based, in draw order) — so a chart can mark the real corners instead of every interpolated sample, and the widget's built-in profile chart marks each corner, labelling the first `1 · Start`. The map badges the first two vertices in draw order (`1 · Start`, `2`), which states the ring's direction outright — a start marker alone leaves clockwise vs counter-clockwise ambiguous, and the two wind to mirror-image profiles. Two badges is the minimum that fixes a direction and a constant cost regardless of how many corners the footprint has. Also volume-only: `deadband` (m³) zeroes out a Cut/Fill figure below the threshold, filtering drag noise near zero height (Cut/Fill/Net/Total are always RAW geometric volumes — deliberately unaffected by `swell`/`shrink`, so they keep answering "does this reach target elevation" regardless of what material's configured); `density` (t/m³ metric, lb/yd³ imperial) and `swell`/`shrink` (multipliers, default 1×) instead populate a separate Material section, standard Bank/Loose/Compacted earthworks convention — Adjusted Cut = raw × swell (loose/haul volume, bigger — excavating adds air voids), Adjusted Fill = raw ÷ shrink (loose/borrow volume needed, also bigger — the raw fill is already the compacted target void), plus Cut/Fill tonnage computed from the raw (not adjusted) volume, since swell/shrink change volume, not mass; the section only appears once at least one of `density`/`swell`/`shrink` is actually configured, no separate toggle. A `stale` field on the `om-measure` readout flags the brief window between a footprint committing and its elevation sample resolving, so a consumer doesn't read numbers left over from a prior footprint as current), `vega-lite` (live charts bound to a layer's data), `dynamic-chart` (the same Vega-Lite rendering, but data-driven by a live DOM event instead of a layer — `on="<event-name>"` + `series-field="<name>"` reads `event.detail[seriesField]` as the chart's `values` on every matching event, redrawing at a fixed `width`; a feature "freezes" it for free by simply omitting that field the next time it fires, no separate pause API needed), and the BIM set `ifc-browser` / `feature-inspector` / `ifc-loader` / `ifc-clash`. Or write your own inline with HTML + a `<script type="om/widget">`. Adjacent compact button widgets (`zoom-controls`, `undo-redo`, `widgets-toggle`) **auto-cluster** into one control group (opt out per widget with `cluster="false"`), and `<om-map widgets-hidden>` / the `set-widgets-visible` action / `<om-widget type="widgets-toggle">` hide all authored chrome without destroying it — provider attribution and the license badge never hide. **Placement is managed**: `position` takes one of 8 logical, RTL-aware slots (`top-start`, `top-center`, `top-end`, `center-start`, `center-end`, `bottom-start`, `bottom-center`, `bottom-end`; legacy corner names alias) — same-slot widgets stack with flush edges and a shared gap, `order` sets in-slot ordering, and `position="manual"` opts out entirely (a plain block you style yourself, even outside the map). At map widths ≤640px, managed widgets automatically move into accessible top/end/bottom/start drawers; `fold="never"` keeps an essential control out, `widgets-fold="off"` disables folding, and `--om-widget-fold-breakpoint` changes the map-width threshold. Provider attribution is an in-flow member of `bottom-end` and the license badge of `bottom-start`, so neither covers a widget. A slot dims automatically while an open popup covers it (`widgets-dim="off"` to disable), except slots containing required chrome. Themeable from plain page CSS via custom properties: `om-map { --om-widget-bg: #111827; --om-widget-fg: #f9fafb; }` (also `-muted`, `-border`, `-hover-bg`, `-accent`), plus layout tokens (`--om-widget-inset-x/-y`, `--om-widget-gap-x/-y`, `--om-widget-opacity`, `--om-widget-radius`) or the no-CSS sugar `<om-map widget-style="gap:10 opacity:0.9">`. |
|
|
88
88
|
| `<om-overlay>` | Rich HTML anchored to a map location — a static `anchor="[lng, lat]"`, the current selection, or a feature's own geometry via `anchor-layer`/`anchor-feature-id`. Selection-anchored overlays scope with `layer` (one layer's picks) and `selection-type="click"`/`"hover"` (one pick type — give a click-opened popup `selection-type="click"` so hovering elsewhere doesn't drag it along). `{{field}}` interpolates the picked feature, HTML-escaped by default; `{{z}}` is a real depth-picked elevation when some layer under the cursor set `pickable="3d"` (terrain does this itself, so hovering the ground always has one) — empty otherwise, never a misleading 0. `clip-to-map` (opt-in) hides the overlay when its own box would spill past the map viewport, not just when its anchor leaves — for small transient tips that track the cursor, where an overhanging box would otherwise inflate the page's scroll overflow and cause visible view jitter. |
|
|
89
89
|
| `<om-behavior>` | Declarative interactions: `on="click|hover|drag|load|data-loaded"` → a named action. |
|
|
@@ -147,7 +147,7 @@ Built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.em
|
|
|
147
147
|
|
|
148
148
|
**Animation:** camera moves accept a duration — `map.flyTo(coords, zoom, { duration: 1200, curve: true })`, or the `fly-to` action (`center`/`zoom`/`pitch`/`bearing`/`duration`) from any behavior or button; `prefers-reduced-motion` is honored (moves become instant, final state identical). Per-prop GPU transitions via the `transition` attribute: `transition="get-fill-color 800ms"` fades color changes; on a streaming layer, `transition="get-position 300ms"` makes entities glide between updates.
|
|
149
149
|
|
|
150
|
-
**Map stories:** a guided tour as markup — `<om-story>` holds `<om-step>` children that fire the same actions behaviors use, on a timeline (`duration`, `delay`, `parallel`); the built-in `type="player"` widget gives play/pause/scrub, seeking restores the scene's captured initial state, one story is active per map, and grabbing the map pauses playback. Effect verbs — `fade`, `pulse`, `trace` (progressive TripsLayer draw-on; with `feature-id`, a single polygon draws itself on inside its own layer), and `populate` (rows drop in one by one via a GPU filter sweep) — work as step shorthands or plain actions. The story is a sibling that references layers by id — delete it and the map is unchanged. For flybys over 3D tilesets, `warm-tiles` pre-loads the route's tiles in the background before playback, and `paced` goes further: the story steps its own clock and never advances a frame while a tileset is still refining, so no frame ever shows unrefined tiles — wall-clock stretches instead (built for recorded takes; emits `om-paced-tick {t, waitedMs}` per frame, and the two compose — warm first, wait less). `npx @nika-js/onlymap record map.html --out flyby.mp4` turns that guarantee into an actual video: one screenshot per paced frame in headless Chromium (widgets and attribution included), assembled with ffmpeg. Guide: [docs/stories.md](docs/stories.md).
|
|
150
|
+
**Map stories:** a guided tour as markup — `<om-story>` holds `<om-step>` children that fire the same actions behaviors use, on a timeline (`duration`, `delay`, `parallel`); the built-in `type="player"` widget gives play/pause/scrub, seeking restores the scene's captured initial state, one story is active per map, and grabbing the map pauses playback. Effect verbs — `fade`, `pulse`, `trace` (progressive TripsLayer draw-on; with `feature-id`, a single polygon draws itself on inside its own layer), and `populate` (rows drop in one by one via a GPU filter sweep) — work as step shorthands or plain actions. The story is a sibling that references layers by id — delete it and the map is unchanged. For flybys over 3D tilesets, `warm-tiles` pre-loads the route's tiles in the background before playback, and `paced` goes further: the story steps its own clock and never advances a frame while a tileset is still refining, so no frame ever shows unrefined tiles — wall-clock stretches instead (built for recorded takes; emits `om-paced-tick {t, waitedMs}` per frame, and the two compose — warm first, wait less). `npx @nika-js/onlymap record map.html --out flyby.mp4` turns that guarantee into an actual video: one screenshot per paced frame in headless Chromium (widgets and attribution included), assembled with ffmpeg — and effect verbs animate on the story clock, so recorded traces draw on frame by frame exactly as authored. Guide: [docs/stories.md](docs/stories.md).
|
|
151
151
|
|
|
152
152
|
**Classified symbology:** `classify-by="magnitude" classify-scale="jenks" classify-classes="5" classify-ramp="viridis"` computes class breaks *from the data* (quantile, equal-interval, or Jenks natural breaks), styles the layer with a named ramp, and auto-generates the classes legend — no domains or colors to hand-author; an explicit `get-fill-color`/`color` always wins. **Temporal playback:** `<om-widget type="time-slider" layer="…" field="time" duration="20s" window="86400000" format="date">` is a play/pause/scrub control over a layer's time field, driving the same `filter-layer` mechanics as the filter widget (stats stay coherent; `loop` restarts the sweep).
|
|
153
153
|
|
package/dist/actions.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The action registry (spec: "Module Breakdown / Behavior Engine" — "Action
|
|
3
|
+
* payload contract"). One event name maps to one action handler with one
|
|
4
|
+
* payload schema, honored identically across all three emit surfaces —
|
|
5
|
+
* `ctx.emit(name, payload)`, `data-emit`, and `<om-behavior>` — an action
|
|
6
|
+
* reads the same keys regardless of how it was triggered. `registerAction`
|
|
7
|
+
* is re-exported from the package entry point (index.ts) as the public
|
|
8
|
+
* `OmMap.registerAction` surface.
|
|
9
|
+
*/
|
|
10
|
+
import { TRACE_TEMP_PREFIX } from "./internal-ids";
|
|
1
11
|
import type { RuntimeCore } from "./runtime-core";
|
|
2
12
|
import type { LayerIR } from "./ir";
|
|
3
13
|
export type ActionHandler = (payload: Record<string, unknown>, mapEl: Element, core: RuntimeCore, layerIRs: ReadonlyMap<string, LayerIR>) => void;
|
|
@@ -9,6 +19,16 @@ export declare function dispatchAction(name: string, payload: Record<string, unk
|
|
|
9
19
|
export { RUNTIME_INTERNAL_PREFIX } from "./internal-ids";
|
|
10
20
|
/** The overlay anchor for a feature: its bbox center for geojson geometry, else its point (flat lon/lat). */
|
|
11
21
|
export declare function featureAnchorPoint(feature: unknown): [number, number] | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Animated-camera payload coercion (spec: "Map Stories / Animation
|
|
24
|
+
* primitives"). Payloads arrive as strings from behavior/step attributes
|
|
25
|
+
* and data-emit, as real values from ctx.emit — coerce both. Durations
|
|
26
|
+
* accept "800", "800ms", or "2s".
|
|
27
|
+
*/
|
|
28
|
+
export declare function cameraOpts(payload: Record<string, unknown>): {
|
|
29
|
+
duration: number;
|
|
30
|
+
curve: boolean;
|
|
31
|
+
};
|
|
12
32
|
/**
|
|
13
33
|
* `trace` — progressive draw. Real tracing needs per-vertex time, which is
|
|
14
34
|
* TripsLayer's whole purpose: sweep `currentTime` across the data's
|
|
@@ -16,6 +36,79 @@ export declare function featureAnchorPoint(feature: unknown): [number, number] |
|
|
|
16
36
|
* back to `fade` with a warning (deck.gl has no dash-offset to fake a
|
|
17
37
|
* draw-on with — documented in the spec).
|
|
18
38
|
*/
|
|
19
|
-
export
|
|
39
|
+
export { TRACE_TEMP_PREFIX };
|
|
40
|
+
export declare function tracedHiddenSet(core: RuntimeCore, layerId: string): Set<string>;
|
|
41
|
+
/** Re-derive the source layer's `data` hide from the current hidden set: nothing hidden clears the hide, else data = rows minus the union. Clears ONLY the data key — a concurrent effect's keys on the same layer (a story-time fade hold, a pulse) must survive the reveal. */
|
|
42
|
+
export declare function applyTraceHide(core: RuntimeCore, ir: LayerIR, rows: readonly unknown[]): void;
|
|
20
43
|
/** Story scrub restore — drop all trace hide bookkeeping for this core (the channel props themselves are cleared separately by cancelAllLayerEffects). */
|
|
21
44
|
export declare function resetTraceHides(core: RuntimeCore): void;
|
|
45
|
+
/**
|
|
46
|
+
* The temp outline layer both trace clocks build (wall-clock traceFeature,
|
|
47
|
+
* story-time EffectTrack): a real runtime-managed <om-layer type="TripsLayer">
|
|
48
|
+
* riding the normal parse → IR → reconcile pipeline.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildTraceTempElement(mapEl: Element, tempId: string, outline: {
|
|
51
|
+
segments: unknown[];
|
|
52
|
+
total: number;
|
|
53
|
+
}, color: unknown): Element;
|
|
54
|
+
/** Fraction of a per-feature trace slot spent drawing; the rest reveals the real feature and dissolves the outline. */
|
|
55
|
+
export declare const TRACE_DRAW_FRACTION = 0.75;
|
|
56
|
+
/**
|
|
57
|
+
* Target resolution both trace clocks share — the two payload shapes
|
|
58
|
+
* (explicit `{ layer, featureId }`, or the pick-derived `{ feature }` a
|
|
59
|
+
* click behavior supplies; picked objects are FLATTENED by the selection
|
|
60
|
+
* path, so the pick only contributes an id and the real row is always
|
|
61
|
+
* looked up from the layer's own data), the row lookup, the outline, and
|
|
62
|
+
* the per-feature temp-layer id. Null = no traceable outline — callers
|
|
63
|
+
* fall back to fade.
|
|
64
|
+
*/
|
|
65
|
+
export interface TraceTarget {
|
|
66
|
+
featureId: string;
|
|
67
|
+
rows: readonly unknown[];
|
|
68
|
+
outline: {
|
|
69
|
+
segments: unknown[];
|
|
70
|
+
total: number;
|
|
71
|
+
};
|
|
72
|
+
tempId: string;
|
|
73
|
+
/** Columnar data never hides (its rows carry no geometry, so the outline already failed there). */
|
|
74
|
+
canHide: boolean;
|
|
75
|
+
}
|
|
76
|
+
export declare function resolveTraceTarget(payload: Record<string, unknown>, ir: LayerIR): TraceTarget | null;
|
|
77
|
+
/**
|
|
78
|
+
* `populate` (spec: "Effect verbs") — rows drop in one by one, the
|
|
79
|
+
* "populate" effect. Rides the ALWAYS-MOUNTED DataFilterExtension (see
|
|
80
|
+
* attribute-resolution): each frame only moves the filterRange upper bound
|
|
81
|
+
* — a uniform update, zero re-upload, the extension's design purpose.
|
|
82
|
+
* Appearance order:
|
|
83
|
+
* - authored `filter-field`: the sweep runs over the AUTHORED range, so
|
|
84
|
+
* rows appear in filter-dimension order and the end state IS the
|
|
85
|
+
* authored filter — nothing to restore;
|
|
86
|
+
* - payload `field`: a one-shot getFilterValue buffer over that field;
|
|
87
|
+
* - neither: data order (ordinal index accessor).
|
|
88
|
+
* GeoJSON without an authored filter falls back to fade: a live composite
|
|
89
|
+
* does not forward a patched getFilterValue to its sub-layers (the
|
|
90
|
+
* per-feature-trace lesson).
|
|
91
|
+
*/
|
|
92
|
+
/** Everything a populate sweep needs, computed once up front — `null` means "no sweepable dimension; fall back to fade" (both clocks share this). */
|
|
93
|
+
export interface PopulateSweep {
|
|
94
|
+
lo: number;
|
|
95
|
+
hi: number;
|
|
96
|
+
accessorPatch?: Record<string, unknown>;
|
|
97
|
+
/** Authored filter dimensions beyond the swept one — held fixed each frame (see the packed filterRange comment below). */
|
|
98
|
+
otherDimRanges?: [number, number][];
|
|
99
|
+
}
|
|
100
|
+
export declare function preparePopulateSweep(payload: Record<string, unknown>, ir: LayerIR): PopulateSweep | null;
|
|
101
|
+
/**
|
|
102
|
+
* The populate sweep's per-frame patch: the accessor patch (same references
|
|
103
|
+
* every frame — the buffer computes once, keyed by its trigger) plus the
|
|
104
|
+
* swept upper bound. With other authored dimensions present, `filterRange`
|
|
105
|
+
* must be the FULL packed array (deck.gl's own multi-dimension shape) — the
|
|
106
|
+
* swept dimension's range first, matching `ir.filter[0]`'s position, then
|
|
107
|
+
* the rest fixed at their authored ranges.
|
|
108
|
+
*/
|
|
109
|
+
export declare function populateSweepFrame(sweep: PopulateSweep, t01: number): Record<string, unknown>;
|
|
110
|
+
/** Timestamp range of a TripsLayer's data via its own compiled getTimestamps accessor — the trace sweep's domain (shared by both trace clocks). */
|
|
111
|
+
export declare function tripsTimestampRange(ir: LayerIR): {
|
|
112
|
+
t0: number;
|
|
113
|
+
t1: number;
|
|
114
|
+
} | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LayerMeta, LayerFilter, LayerCategoryFilter } from "./ir";
|
|
1
|
+
import type { LayerMeta, LayerFilter, LayerCategoryFilter, LayerData } from "./ir";
|
|
2
2
|
import type { LayerSchema, PropDescriptor } from "./layer-registry";
|
|
3
3
|
import type { Shape } from "./expr";
|
|
4
4
|
/** Sweeps the shared caches down to exactly the keys still referenced by the current manifest (Q4). */
|
|
@@ -39,8 +39,49 @@ export declare function kebabToCamel(name: string): string;
|
|
|
39
39
|
export declare const DASH_ATTRS: Set<string>;
|
|
40
40
|
/** Classified symbology (spec: issue #12; src/classify.ts) — universal layer attributes like `filter-*`, resolved where the data is in hand (parse-manifest / descriptorToIR), never per-schema deck props. */
|
|
41
41
|
export declare const CLASSIFY_ATTRS: Set<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Per-layer zoom visibility (public issue #38) — a universal layer
|
|
44
|
+
* attribute honoured on EVERY layer type: `visible-zoom-range="[8, 14]"`
|
|
45
|
+
* hides the layer outside min ≤ zoom < max (the minzoom/maxzoom convention
|
|
46
|
+
* every web-map stack uses — Mapbox/MapLibre semantics, so translated
|
|
47
|
+
* manifests behave identically). Scale-dependent visibility is the everyday
|
|
48
|
+
* GIS concept; deck's own visible-*-zoom props exist only on tile layers.
|
|
49
|
+
* The gate composes with (never overrides) authored `visible`.
|
|
50
|
+
*/
|
|
51
|
+
export declare const ZOOM_VISIBILITY_ATTR = "visible-zoom-range";
|
|
52
|
+
/** Pure coercion (no console) — validation.ts shares it so validate() reports the same malformed shapes structurally. */
|
|
53
|
+
export declare function coerceVisibleZoomRange(raw: unknown): [number, number] | undefined;
|
|
54
|
+
export declare function parseVisibleZoomRange(raw: unknown, warnLabel: string): [number, number] | undefined;
|
|
55
|
+
/** The gate itself — min inclusive, max exclusive (minzoom/maxzoom convention). */
|
|
56
|
+
export declare function zoomInVisibleRange(range: [number, number], zoom: number): boolean;
|
|
42
57
|
/** Layer types whose deck class strokes a path, so PathStyleExtension's dash takes effect (GeoJsonLayer/PolygonLayer dash their line/stroke sublayers). */
|
|
43
58
|
export declare const DASH_CAPABLE_LAYERS: Set<string>;
|
|
59
|
+
/** A ValidationEntry-compatible shape, structural to avoid the validation.ts import cycle. */
|
|
60
|
+
interface AccessorWarningSink {
|
|
61
|
+
(entry: {
|
|
62
|
+
severity: "warning";
|
|
63
|
+
element: string;
|
|
64
|
+
attribute: string;
|
|
65
|
+
message: string;
|
|
66
|
+
fix: string;
|
|
67
|
+
}): void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Public issue #39: a standalone TextLayer fed GeoJSON with no get-position
|
|
71
|
+
* renders NOTHING, silently — deck's default accessor (`x => x.position`)
|
|
72
|
+
* resolves undefined for every feature and the glyphs cull. The identical
|
|
73
|
+
* mistake THROWS on columnar data, so the silence is an asymmetry, not a
|
|
74
|
+
* policy. This samples the first row through the deck DEFAULT for every
|
|
75
|
+
* schema-required accessor the author did not claim: a defined result means
|
|
76
|
+
* the default genuinely works (flat rows with a `position` field — stay
|
|
77
|
+
* silent), an undefined one means nothing will draw — warn, with the exact
|
|
78
|
+
* fix. Columnar is skipped (deck already errors loudly there), as is
|
|
79
|
+
* URL-backed data that hasn't arrived (rows resolve on the reparse).
|
|
80
|
+
*
|
|
81
|
+
* `OmMap.validate()` keeps its stricter unconditional required-accessor
|
|
82
|
+
* ERROR — this is the runtime twin for authors who never call validate.
|
|
83
|
+
*/
|
|
84
|
+
export declare function warnUnresolvedRequiredAccessors(schema: LayerSchema, props: Record<string, unknown>, data: LayerData, shape: Shape, elementDesc: string, report?: AccessorWarningSink): void;
|
|
44
85
|
/** A dash pattern authored as a JSON array (`[6, 3]`) OR an SVG-style token list (`6 3`, `6,3`) → `[dashLength, gapLength]`; undefined if it isn't two finite positive numbers. */
|
|
45
86
|
export declare function parseDashArray(raw: string): [number, number] | undefined;
|
|
46
87
|
/** Already-coerced dash declaration — attribute strings (DOM) or typed values (programmatic). */
|
|
@@ -206,6 +247,18 @@ export declare const FULL_JS_COLUMNAR_RULE: {
|
|
|
206
247
|
};
|
|
207
248
|
/** Coerce a raw attribute string to a primitive: bare/true/false, JSON array/object, number, or string. */
|
|
208
249
|
export declare function coerceValue(raw: string, hint?: PropDescriptor["type"], attrName?: string): unknown;
|
|
250
|
+
/**
|
|
251
|
+
* Schema defaults must be assigned BY VALUE: several descriptors carry
|
|
252
|
+
* deck's own defaultProps objects (e.g. `extensions: []`), and assigning
|
|
253
|
+
* that array by reference aliases it across EVERY layer of the type — one
|
|
254
|
+
* layer's extension push then mutates deck's class default and leaks into
|
|
255
|
+
* all siblings (found via the atlas demo: a trace temp that verifiably
|
|
256
|
+
* skipped filter wiring still built with a DataFilterExtension, because the
|
|
257
|
+
* defaults pass handed it the type's shared, already-polluted array).
|
|
258
|
+
* Shallow clone is exactly right: entries (extension instances) may share,
|
|
259
|
+
* the CONTAINER must not.
|
|
260
|
+
*/
|
|
261
|
+
export declare function cloneDefault(value: unknown): unknown;
|
|
209
262
|
export interface ResolvedAttributes {
|
|
210
263
|
props: Record<string, unknown>;
|
|
211
264
|
meta: LayerMeta;
|
|
@@ -219,3 +272,4 @@ export interface ResolvedAttributes {
|
|
|
219
272
|
categoryFilter?: LayerCategoryFilter;
|
|
220
273
|
}
|
|
221
274
|
export declare function resolveLayerAttributes(el: Element, schema: LayerSchema, shape: Shape): ResolvedAttributes;
|
|
275
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ny, L as sy, M as oy, m as ay, c as ka, a as Sd, z as oc, G as sm, V as ly, W as cy, b as uy, g as hy, d as Vu, f as Ed, e as dy, l as py, u as fy, D as Qf, h as my } from "./index-
|
|
1
|
+
import { C as ny, L as sy, M as oy, m as ay, c as ka, a as Sd, z as oc, G as sm, V as ly, W as cy, b as uy, g as hy, d as Vu, f as Ed, e as dy, l as py, u as fy, D as Qf, h as my } from "./index-Ddn4yvyL.js";
|
|
2
2
|
const Cd = Math.PI / 180, gy = 180 / Math.PI;
|
|
3
3
|
function em(Pe, J = 0) {
|
|
4
4
|
const me = Math.min(180, Pe) * Cd;
|
|
@@ -25321,7 +25321,7 @@ class Ry {
|
|
|
25321
25321
|
Me && me > 0 ? this.map.flyTo(Te) : this.map.easeTo(Te);
|
|
25322
25322
|
}
|
|
25323
25323
|
fitBounds(J, me, Me = 0) {
|
|
25324
|
-
this.map.fitBounds(J, { padding: me, duration: Me });
|
|
25324
|
+
this.markBusy(), this.map.fitBounds(J, { padding: me, duration: Me });
|
|
25325
25325
|
}
|
|
25326
25326
|
destroy() {
|
|
25327
25327
|
if (this.pendingCaptureRejects.size > 0) {
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
* CPU-side mirror of the GPU `DataFilterExtension` test (spec: "Filter-aware
|
|
3
|
-
* stats & data (the coherence rule)") — `ctx.stats`/`ctx.dataInViewport`
|
|
4
|
-
* apply the SAME field+range/category test(s) by default, so a chart/stat
|
|
5
|
-
* reflects what the map visibly shows. A row whose field isn't a finite
|
|
6
|
-
* number (numeric) or isn't in the keep-list (categorical) is treated as
|
|
7
|
-
* filtered-out, matching the GPU path. With more than one dimension of
|
|
8
|
-
* EITHER kind a row passes only if every dimension's test passes (AND
|
|
9
|
-
* across dimensions) — the same semantics deck.gl's own packed
|
|
10
|
-
* `filterRange`/`filterCategories` arrays apply GPU-side. Numeric and
|
|
11
|
-
* categorical are independent mechanisms (see `applyFilterWiring`'s doc
|
|
12
|
-
* comment) but combine the same way: a row must pass BOTH kinds when both
|
|
13
|
-
* are active on a layer.
|
|
14
|
-
*/
|
|
15
|
-
import type { Shape, LayerFilter, LayerCategoryFilter } from "./ir";
|
|
1
|
+
import type { Shape, LayerFilter, LayerCategoryFilter, LayerData } from "./ir";
|
|
16
2
|
export declare function applyDeclarativeFilter(rows: readonly unknown[], shape: Shape, filter: LayerFilter): unknown[];
|
|
17
3
|
/** The same test as a reusable predicate — the columnar viewport filter runs it inside its index-aligned loop. */
|
|
18
4
|
export declare function declarativeFilterPredicate(shape: Shape, filter: LayerFilter): (row: unknown) => boolean;
|
|
19
5
|
export declare function applyDeclarativeCategoryFilter(rows: readonly unknown[], shape: Shape, categoryFilter: LayerCategoryFilter): unknown[];
|
|
20
6
|
/** Categorical twin of `declarativeFilterPredicate` — set membership instead of a range test. */
|
|
21
7
|
export declare function declarativeCategoryFilterPredicate(shape: Shape, categoryFilter: LayerCategoryFilter): (row: unknown) => boolean;
|
|
22
|
-
export declare function warnCategoryCardinality(categoryFilter: LayerCategoryFilter | undefined,
|
|
8
|
+
export declare function warnCategoryCardinality(categoryFilter: LayerCategoryFilter | undefined, data: LayerData, shape: Shape, warnLabel: string): void;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story-time effect evaluation (spec: "Map Stories" / issue #37's pull
|
|
3
|
+
* model, completed for layer effects). `buildCameraLegs`/`cameraAtTime`
|
|
4
|
+
* already make the camera a pure function of story time; this module does
|
|
5
|
+
* the same for the animated verbs (fade / pulse / trace / populate). When
|
|
6
|
+
* the story owns the clock — a paced story (the recorder) or the
|
|
7
|
+
* determinism switch (frame renderers seeking) — those steps are NOT
|
|
8
|
+
* dispatched as actions: the story builds one EffectTrack from its timeline
|
|
9
|
+
* and evaluates every leg at the current story time on each tick or seek.
|
|
10
|
+
* A trace 40% drawn is then just a scene, reproducible at any t, instead
|
|
11
|
+
* of a wall-clock rAF loop racing the capture.
|
|
12
|
+
*
|
|
13
|
+
* Interactive wall-clock playback is untouched: it keeps dispatching the
|
|
14
|
+
* verbs through actions.ts, whose rAF path (effects.ts) remains the clock
|
|
15
|
+
* for anything without a timeline (click-to-trace behaviors, ctx.emit).
|
|
16
|
+
* Both clocks share the same underlying builders — the pure math
|
|
17
|
+
* (traceProgress, pulseOpacity, EASINGS), the populate sweep, the trace
|
|
18
|
+
* target/temp element — so a verb renders identically whichever clock
|
|
19
|
+
* drives it.
|
|
20
|
+
*
|
|
21
|
+
* Evaluation contract: legs are stateless functions of t, EXCEPT the
|
|
22
|
+
* documented enter/exit hooks (temp-layer DOM, trace hide sets), which the
|
|
23
|
+
* evaluator invokes on phase transitions. Seek resets are handled by the
|
|
24
|
+
* story's existing scrub model — restore-initial clears every channel patch
|
|
25
|
+
* and temp layer, then resetState() forgets all phases and applyAt(t)
|
|
26
|
+
* rebuilds the scene from pristine. Follow cameras are the one exception:
|
|
27
|
+
* during a paced run the driver owns the camera, so `follow` is skipped
|
|
28
|
+
* (warned once per track).
|
|
29
|
+
*/
|
|
30
|
+
import type { RuntimeCore } from "./runtime-core";
|
|
31
|
+
import type { LayerIR } from "./ir";
|
|
32
|
+
import type { StepInterval } from "./timeline";
|
|
33
|
+
/** The verbs the track owns — fireDueSteps suppresses exactly these while the story clock drives effects. */
|
|
34
|
+
export declare const EFFECT_TRACK_ACTIONS: Set<string>;
|
|
35
|
+
export interface EffectTrackDeps {
|
|
36
|
+
core: RuntimeCore;
|
|
37
|
+
mapEl: Element;
|
|
38
|
+
/**
|
|
39
|
+
* LIVE accessor, never a snapshot: om-map REASSIGNS its IR map on every
|
|
40
|
+
* reconcile (`this.layerIRs = next`), so a captured reference goes stale
|
|
41
|
+
* after the first reconcile of a run — which is guaranteed (the trace
|
|
42
|
+
* leg's own temp-element append triggers one). Legs re-init when a
|
|
43
|
+
* layer's data identity changes (URL arrival), which only works read
|
|
44
|
+
* through here.
|
|
45
|
+
*/
|
|
46
|
+
getLayerIRs(): ReadonlyMap<string, LayerIR>;
|
|
47
|
+
}
|
|
48
|
+
/** A leg's resolved behavior — chosen lazily on first need, when the layer's data is in hand. */
|
|
49
|
+
interface LegImpl {
|
|
50
|
+
/** Eased t01 → per-layer patches (the same shapes the wall-clock path writes through patchAnimatedProps). */
|
|
51
|
+
frame(t01: number): Record<string, Record<string, unknown>>;
|
|
52
|
+
/** "hold": past the leg, keep frame(1) applied. "clear": past the leg, the authored state IS the end state. */
|
|
53
|
+
end: "hold" | "clear";
|
|
54
|
+
/** Phase-entry hook (idempotent per activation): temp layers, trace hides. */
|
|
55
|
+
enter?(): void;
|
|
56
|
+
/** Phase-exit hook: teardown of whatever enter() built. */
|
|
57
|
+
exit?(): void;
|
|
58
|
+
}
|
|
59
|
+
interface Leg {
|
|
60
|
+
layerId: string;
|
|
61
|
+
start: number;
|
|
62
|
+
duration: number;
|
|
63
|
+
easing?: (t: number) => number;
|
|
64
|
+
init(deps: EffectTrackDeps): LegImpl | null;
|
|
65
|
+
}
|
|
66
|
+
export declare class EffectTrack {
|
|
67
|
+
private readonly legs;
|
|
68
|
+
private readonly deps;
|
|
69
|
+
private states;
|
|
70
|
+
/** Set by deactivate() (including ensureImpl's re-init teardown) — the heal pass re-applies what a removeEffectKeys may have stripped from a shared layer. */
|
|
71
|
+
private keysRemoved;
|
|
72
|
+
constructor(legs: Leg[], deps: EffectTrackDeps);
|
|
73
|
+
/** Forget all phase state WITHOUT teardown — call only after the story's restore-initial has already cleared patches and temp layers. */
|
|
74
|
+
resetState(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Evaluate every leg at story time t. CONTRACT: t is monotonically
|
|
77
|
+
* non-decreasing between resetState() calls — every caller guarantees it
|
|
78
|
+
* (advanceBy is monotone; seek and the loop restart reset first), so
|
|
79
|
+
* phases only ever move forward here and no backward transition exists.
|
|
80
|
+
* Legs are pre-sorted by start, so cross-leg chains resolve in timeline
|
|
81
|
+
* order.
|
|
82
|
+
*/
|
|
83
|
+
applyAt(t: number): void;
|
|
84
|
+
/** Re-applies leg i's current value: frame(1) for a settled hold, the eased frame at t for an active leg, nothing otherwise. Idempotent. */
|
|
85
|
+
private applyLegFrame;
|
|
86
|
+
private ensureImpl;
|
|
87
|
+
private apply;
|
|
88
|
+
private deactivate;
|
|
89
|
+
}
|
|
90
|
+
export declare function buildEffectTrack(steps: readonly {
|
|
91
|
+
action: string;
|
|
92
|
+
payload: Record<string, unknown>;
|
|
93
|
+
}[], intervals: readonly StepInterval[], deps: EffectTrackDeps): EffectTrack;
|
|
94
|
+
export {};
|
package/dist/effects.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export declare const EASINGS: Record<string, (t: number) => number>;
|
|
|
18
18
|
export declare function traceProgress(t01: number, t0: number, t1: number): number;
|
|
19
19
|
/** Oscillates 1 → low → 1 per cycle (cosine), ending exactly at 1 for whole cycles. */
|
|
20
20
|
export declare function pulseOpacity(t01: number, cycles: number, low?: number): number;
|
|
21
|
+
/** Removes exactly one effect's keys from the layer's channel entry, preserving keys other writers own. (Exported for the story-time EffectTrack, which manages its own written-key sets.) */
|
|
22
|
+
export declare function removeEffectKeys(core: RuntimeCore, layerId: string, keys: Set<string>): void;
|
|
21
23
|
export declare function prefersReducedMotion(): boolean;
|
|
22
24
|
export interface LayerEffect {
|
|
23
25
|
/** t01 ∈ [0, 1] → the plain-prop patch for this frame. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTMLElementBase } from "../env";
|
|
2
|
+
import { RuntimeCore } from "../runtime-core";
|
|
2
3
|
import { type RuntimeContext } from "../ctx";
|
|
3
4
|
import { type LightingIR } from "../scene-lighting";
|
|
4
5
|
import { type ClipBoxIR } from "../clip-box";
|
|
@@ -54,7 +55,6 @@ export declare class OmMapElement extends HTMLElementBase {
|
|
|
54
55
|
/** Dedup guard for the no-terrain-for-elevation error — same shape as `warnedApproximatePlacement`. */
|
|
55
56
|
private erroredNoTerrainForElevation;
|
|
56
57
|
private readyFired;
|
|
57
|
-
private firstSettleDrawDone;
|
|
58
58
|
/** Custom-state holder for the `om-collapsed` height-floor marker — see applyHeightFloor. */
|
|
59
59
|
private internals;
|
|
60
60
|
private resolveReady;
|
|
@@ -260,13 +260,8 @@ export declare class OmMapElement extends HTMLElementBase {
|
|
|
260
260
|
* same path a real deck click/hover coordinate takes, so the om-map-point
|
|
261
261
|
* event and custom capture tools are testable without a GPU. */
|
|
262
262
|
/**
|
|
263
|
-
* The map's "done drawing" promise (issue #37)
|
|
264
|
-
*
|
|
265
|
-
* frame has been painted — the await a pull-model frame renderer (or a
|
|
266
|
-
* consumer Playwright test) needs before screenshotting. Resolves
|
|
267
|
-
* `{settled:false}` with a console warning on timeout rather than
|
|
268
|
-
* rejecting (a late frame is ordinary pop-in, not an error). v1 gates 3D
|
|
269
|
-
* tilesets only — basemap raster tiles are not yet awaited.
|
|
263
|
+
* The map's "done drawing" promise (issue #37) — delegates to
|
|
264
|
+
* RuntimeCore.whenSettled, the single owner of the settle contract.
|
|
270
265
|
*/
|
|
271
266
|
whenSettled(opts?: {
|
|
272
267
|
timeout?: number;
|
|
@@ -275,6 +270,12 @@ export declare class OmMapElement extends HTMLElementBase {
|
|
|
275
270
|
}>;
|
|
276
271
|
/** Test surface: is the determinism switch active on the core (issue #37 — must be true BEFORE the first render when data-om-recording is authored; the basemap adapter reads it in its constructor). */
|
|
277
272
|
isDeterministicInternal(): boolean;
|
|
273
|
+
/** What the story-time EffectTrack needs to evaluate legs (om-story builds one when the story clock owns effects — paced stories, determinism). getLayerIRs is a LIVE accessor: reconcile REASSIGNS this.layerIRs, so a captured map reference would go stale after the first reconcile of a run. */
|
|
274
|
+
getEffectDepsInternal(): {
|
|
275
|
+
core: RuntimeCore;
|
|
276
|
+
mapEl: Element;
|
|
277
|
+
getLayerIRs(): ReadonlyMap<string, LayerIR>;
|
|
278
|
+
} | null;
|
|
278
279
|
injectMapPointInternal(coordinate: [number, number] | null, kind?: "click" | "hover", pointerType?: string): void;
|
|
279
280
|
/** Harness setView (spec: "Consumer Testing Surface") — the one path that reaches pitch/bearing. */
|
|
280
281
|
setViewInternal(partial: {
|
|
@@ -15,6 +15,8 @@ export declare class OmStoryElement extends HTMLElementBase {
|
|
|
15
15
|
private pacedGen;
|
|
16
16
|
/** True while the paced driver owns the camera — fireDueSteps must not dispatch camera actions against it. */
|
|
17
17
|
private pacedDriving;
|
|
18
|
+
/** Story-time effect evaluation (effect-track.ts) — built lazily when the story clock owns effects, invalidated whenever steps rebuild. */
|
|
19
|
+
private effectTrack;
|
|
18
20
|
private warnedPacedCameraSkip;
|
|
19
21
|
private pacedCapture;
|
|
20
22
|
private captured;
|
|
@@ -64,6 +66,22 @@ export declare class OmStoryElement extends HTMLElementBase {
|
|
|
64
66
|
*/
|
|
65
67
|
private startPaced;
|
|
66
68
|
private advanceBy;
|
|
69
|
+
/**
|
|
70
|
+
* The story clock owns effects when playback is pull-model: a PACED STORY
|
|
71
|
+
* (the recorder — wall-clock rAF effects would race the capture clock) or
|
|
72
|
+
* the determinism switch (frame renderers seek; runLayerEffect snaps
|
|
73
|
+
* there). Keyed on the `paced` ATTRIBUTE, deliberately not the transient
|
|
74
|
+
* pacedDriving flag: the flag drops asynchronously on pause, and a
|
|
75
|
+
* scrubber seek in that window would otherwise dispatch the verbs
|
|
76
|
+
* wall-clock (stamping end-state attributes, starting real rAF runners)
|
|
77
|
+
* that the resumed track then double-drives. The clock authority must be
|
|
78
|
+
* stable for a whole playback; flipping it mid-story is out of contract
|
|
79
|
+
* (the next seek re-evaluates cleanly). Interactive wall-clock playback
|
|
80
|
+
* keeps dispatching the verbs as actions — the rAF path in effects.ts is
|
|
81
|
+
* untouched.
|
|
82
|
+
*/
|
|
83
|
+
private storyClockOwnsEffects;
|
|
84
|
+
private ensureEffectTrack;
|
|
67
85
|
private fireDueSteps;
|
|
68
86
|
/** Steps and the timeline are (re)built lazily when idle — mid-play DOM edits apply on the next play/seek. */
|
|
69
87
|
private ensureBuilt;
|
package/dist/html-data.d.ts
CHANGED
|
@@ -22,4 +22,18 @@ export declare function buildHtmlCustomData(): {
|
|
|
22
22
|
version: number;
|
|
23
23
|
tags: TagData[];
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Machine-readable per-layer-type attribute contract (public issue #38) —
|
|
27
|
+
* shipped as `onlymapjs.attributes.json`. The html-customData format cannot
|
|
28
|
+
* scope an attribute to a `type=` value, so a CI check validating emitted
|
|
29
|
+
* markup against the flat union passes attributes the runtime rejects (the
|
|
30
|
+
* QGIS2WebMap visible-min-zoom case; #36's dash hid in the same gap).
|
|
31
|
+
* Generated from the SAME registry the runtime's typo-check validates
|
|
32
|
+
* against, so the two cannot drift: an attribute is accepted on a type iff
|
|
33
|
+
* it is in `universal` or in `layers[<type>]`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildLayerAttributeContract(): {
|
|
36
|
+
universal: string[];
|
|
37
|
+
layers: Record<string, string[]>;
|
|
38
|
+
};
|
|
25
39
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ak as Bt, ax as Xt, ay as Yt, az as Us } from "./index-
|
|
1
|
+
import { ak as Bt, ax as Xt, ay as Yt, az as Us } from "./index-Ddn4yvyL.js";
|
|
2
2
|
import { w as gs, t as Hs, f as Ws, m as Qs } from "./mgrs-BY9bIvp4.js";
|
|
3
3
|
import { c as Xs } from "./convert-arrow-schema-DrAihRf9.js";
|
|
4
4
|
import { y as Ys, A as bt, a as Ks, z as Vs, R as Zs } from "./recordbatch-Bpc0uxFn.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as E, j as S, k as R, o as N, p as h, q as w, s as O, t as W, v as x, w as I, x as B, y as _, A as P, B as k, E as $, F as z, H as v, I as F, J as C, K as U, N as p, O as M } from "./index-
|
|
2
|
-
import { P as $e, R as ze, _ as ve, Q as Ce, S as Ue, T as Me, U as je, X as De, Y as Je, Z as qe, $ as He, a0 as Ve, a1 as Ge, a2 as Ke, a3 as Qe, a4 as Xe, a5 as Ye, a6 as Ze, a7 as et, a8 as tt, a9 as nt, aa as rt, ab as at, ac as st, ad as ot } from "./index-
|
|
1
|
+
import { i as E, j as S, k as R, o as N, p as h, q as w, s as O, t as W, v as x, w as I, x as B, y as _, A as P, B as k, E as $, F as z, H as v, I as F, J as C, K as U, N as p, O as M } from "./index-Ddn4yvyL.js";
|
|
2
|
+
import { P as $e, R as ze, _ as ve, Q as Ce, S as Ue, T as Me, U as je, X as De, Y as Je, Z as qe, $ as He, a0 as Ve, a1 as Ge, a2 as Ke, a3 as Qe, a4 as Xe, a5 as Ye, a6 as Ze, a7 as et, a8 as tt, a9 as nt, aa as rt, ab as at, ac as st, ad as ot } from "./index-Ddn4yvyL.js";
|
|
3
3
|
import { g as j, i as D } from "./table-accessors-CYWTzpQI.js";
|
|
4
4
|
async function J(t, e, n = {}, r = {}) {
|
|
5
5
|
const a = E(t), s = S.getWorkerFarm(n), { source: o } = n, c = { name: a, source: o };
|