@nika-js/onlymap 0.6.11 → 0.6.14
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 +23 -0
- package/README.md +16 -2
- package/dist/{LercDecode.es-C331HMjV.js → LercDecode.es-Bqk5xyNu.js} +1 -1
- package/dist/attribute-resolution.d.ts +4 -0
- package/dist/{basemap-NN5SYEaS.js → basemap-KDsE62YN.js} +1 -1
- package/dist/classify.d.ts +62 -0
- package/dist/clip-box.d.ts +0 -32
- package/dist/data-layer.d.ts +0 -17
- package/dist/draw-controller.d.ts +4 -1
- package/dist/effects.d.ts +1 -0
- package/dist/elements/om-map.d.ts +1 -21
- package/dist/elements/om-story.d.ts +0 -18
- package/dist/expr/errors.d.ts +3 -0
- package/dist/field-access.d.ts +10 -0
- package/dist/geodesy.d.ts +11 -0
- package/dist/{geoparquet-Dmyu5Oou.js → geoparquet-DOexUItM.js} +1 -1
- package/dist/html-data.d.ts +1 -1
- package/dist/{index-D28RTVKt.js → index-BFNjPrc2.js} +1 -1
- package/dist/{index-CSVtCpQL.js → index-D_EyImRx.js} +1 -1
- package/dist/{index-_vNbcONa.js → index-DnsWPk6e.js} +1 -1
- package/dist/{index-BUp4hR6r.js → index-ESUJidEA.js} +21949 -21687
- package/dist/{index-CNxSRD27.js → index-mxTk4d2L.js} +2 -2
- package/dist/layer-registry.d.ts +10 -0
- package/dist/layers/marker-icons.d.ts +0 -2
- package/dist/legend-spec.d.ts +1 -6
- package/dist/{lerc-Cryu98-R.js → lerc-CPb8TKuv.js} +2 -2
- package/dist/onlymap.standalone.js +41385 -41123
- package/dist/onlymapjs.js +1 -1
- package/dist/programmatic.d.ts +5 -16
- package/dist/{raster-BVzTnbhW.js → raster-M2R7FhL7.js} +2 -2
- package/dist/{raster-pipeline-FAPzre9S.js → raster-pipeline-Csa7n5SZ.js} +1 -1
- package/dist/react.js +215 -232
- package/dist/runtime-core.d.ts +35 -1
- package/dist/site-placement.d.ts +0 -2
- package/dist/testing.d.ts +4 -1
- package/dist/version.d.ts +1 -1
- package/dist/{zarr-DCWSzKoG.js → zarr-tHnzENgX.js} +2 -2
- package/docs/testing.md +1 -1
- package/llms.txt +5 -3
- package/onlymapjs.html-data.json +32 -1
- package/package.json +3 -2
- package/skills/onlymapjs/SKILL.md +5 -4
- package/skills/onlymapjs/references/syntax.md +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,29 @@ 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.14 — 2026-08-21
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Dashed lines render again.** `dash="[4, 2]"` had been drawing solid lines since 0.6.2 — the terrain patch merge was unintentionally stripping every layer's extensions on flat maps (issue #36).
|
|
15
|
+
- **Filters visibly apply again on maps without terrain** — same underlying cause as the dash fix. Filter widgets and statistics were always correct; the map itself just wasn't hiding filtered-out features.
|
|
16
|
+
- **Maps built in code now match maps built in HTML.** Built-in defaults apply (e.g. BIM models are clickable by default), `{z}/{x}/{y}` tile URLs load as tiles instead of failing, legends generate automatically, and `classifyBy` now works in React.
|
|
17
|
+
- **`snap="false"` and `clip="false"` now opt a layer out**, matching what validation already accepted; `snap="off"` / `clip="off"` unchanged.
|
|
18
|
+
|
|
19
|
+
## 0.6.13 — 2026-08-20
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Line/polygon completion now works on iOS WebViews** (issue #17) — iOS never synthesizes `dblclick` from a double-tap while touch handlers are active, so double-tap added two more vertices instead of committing (Android committed fine — platform-inconsistent). The draw controller now detects the tap pair itself (two touch/pen taps within 350ms and ~12px) and completes the shape; mouse input keeps the native `dblclick` path, and synthetic/programmatic picks (no `pointerType`) opt into nothing. Applies wherever the draw stack runs, including the measure widget's footprints.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- **Finish button on the draw toolbar** — an explicit, discoverable completion affordance (double-click/double-tap/Enter are conventions the user must already know); harmless no-op when nothing is pending.
|
|
26
|
+
- **`mapPoint(coord, kind, pointerType?)`** on the test harness — simulate a specific input modality (`"touch"`/`"pen"`/`"mouse"`) through the real pick path.
|
|
27
|
+
|
|
28
|
+
## 0.6.12 — 2026-08-19
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Classified symbology** (issue #12) — `classify-by="magnitude" classify-scale="quantile|equal-interval|jenks" classify-classes="5" classify-ramp="viridis"` computes class breaks *from the data* at reconcile time, installs the fill-color accessor, and auto-generates the classes legend. Fourteen named ramps (matplotlib + ColorBrewer). An authored `get-fill-color`/`color` always wins (validation names the conflict); URL-backed layers classify when their data arrives; results are memoized per data reference so deck recomputes exactly when the classification genuinely changes. Mirrored on the programmatic front-end as `classifyBy`/`classifyScale`/`classifyClasses`/`classifyRamp`.
|
|
32
|
+
- **`time-slider` widget** (issue #18) — play/pause/scrub playback over a layer's numeric/epoch-ms time field: `<om-widget type="time-slider" layer="quakes" field="time" duration="20s" window="86400000" loop format="date">`. Drives the ordinary `filter-layer` action (cumulative from the domain start, or a sliding `window` in field units), so widget statistics stay coherent and undo/stories/external filter edits re-sync the thumb; date labels reuse the filter widget's `format`/`date-style`/`time-zone` contract.
|
|
33
|
+
|
|
11
34
|
## 0.6.11 — 2026-08-18
|
|
12
35
|
|
|
13
36
|
### Fixed
|
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ A handful of elements, one rule: **attributes are kebab-case versions of deck.gl
|
|
|
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
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. |
|
|
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; `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 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">`. |
|
|
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. |
|
|
90
90
|
| `<om-story>` | A storyboard: `<om-step>` children fire actions on a timeline. Controlled by the `player` widget, behaviors, or `storyEl.play()/pause()/seek()`. |
|
|
@@ -149,6 +149,8 @@ Built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.em
|
|
|
149
149
|
|
|
150
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. Guide: [docs/stories.md](docs/stories.md).
|
|
151
151
|
|
|
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
|
+
|
|
152
154
|
GPU filtering is declarative — `filter-field="magnitude" filter-range="[4,10]"` — updates live from the built-in `filter` widget (a slider), and widget statistics stay coherent with what the map shows (`ctx.stats` respects the active filter unless you opt out). Up to 4 numeric dimensions at once via `filter-fields='[{"field":"magnitude","range":[4,10]},{"field":"time","range":[…]}]'` — a widget per field, each moved independently; a row must pass every active dimension. Categorical filtering is the same shape, a separate mechanism — `filter-category="fuel" filter-categories="[...]"` (or `filter-category-fields` for up to 4) renders the same `filter` widget as a checkbox list instead of a slider, and combines with any active numeric filter (a row must pass both).
|
|
153
155
|
|
|
154
156
|
Dashed lines are one attribute — `dash="[6, 3]"` (or `dash="6 3"`, plus optional `dash-justified`) on a `PathLayer`/`GeoJsonLayer`/`PolygonLayer`/`TripsLayer` — wired through deck's `PathStyleExtension` under the hood.
|
|
@@ -195,6 +197,18 @@ That opt-in command updates `.vscode/settings.json` and copies the `!`-prefixed
|
|
|
195
197
|
|
|
196
198
|
The package also ships `!`-prefixed manifest snippets (`node_modules/@nika-js/onlymap/.vscode/onlymap.code-snippets`) — type `!starter`, `!map`, `!layer`, `!draw`, etc. to scaffold a well-formed element.
|
|
197
199
|
|
|
200
|
+
## React Native / mobile
|
|
201
|
+
|
|
202
|
+
The same runtime ships as an Expo React Native adapter,
|
|
203
|
+
[`@nika-js/onlymap-native`](https://github.com/NikaGeospatial/onlymap-native)
|
|
204
|
+
— the complete library hosted in a secure WebView and driven from JSX over a
|
|
205
|
+
JSON bridge. The native surface keeps OnlyMap's vocabulary with two rule
|
|
206
|
+
changes: accessors are **expression strings** (`getPosition="[$lon, $lat]"` —
|
|
207
|
+
functions cannot cross the bridge) and everything on a descriptor is plain
|
|
208
|
+
JSON. A 20-fixture parity gate keeps the native lane byte-identical to this
|
|
209
|
+
repo's React adapter at the IR level. Guide:
|
|
210
|
+
[docs.nikaplanet.com → OnlyMap JS → React Native](https://docs.nikaplanet.com/onlymap/react-native).
|
|
211
|
+
|
|
198
212
|
## Quick-start guide
|
|
199
213
|
|
|
200
214
|
### Use OnlyMapJS with Claude Code and Codex
|
|
@@ -327,7 +341,7 @@ The library reports one **deployment-scoped** usage snapshot per map per page lo
|
|
|
327
341
|
|
|
328
342
|
## Not implemented yet (honestly)
|
|
329
343
|
|
|
330
|
-
Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, `dblclick` behaviors, the `transform` data pipeline, the typed fluent builder, and stories/draw as React components (both work via the HTML manifest). On `pick-features`: instanced (i3dm) tiles keep tile-granularity picking, and `feature-styles`' `opacity` below 1 is still being validated. On BIM: clash detection is bounding-box only (no mesh-level test, and it cannot tell a resolved penetration from a collision), there is no BCF export, no equivalent of Navisworks' Auto Reveal, and prepared tilesets converted before the `bbox*` columns existed cannot take part in a clash pass — `strength` tinting and `opacity: 0` (hide, a shader discard) work. On the measure widget's `volume` mode: the per-cell grid integration measures against the map's active terrain DEM only — measuring against an imported design surface or a previous survey (period-over-period reconciliation) and a cut/fill heat-map overlay are not implemented yet, and a snapped footprint vertex takes the matched feature's horizontal position only — its exact elevation is not threaded through (see **XY snapping** above).
|
|
344
|
+
Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, `dblclick` behaviors, the `transform` data pipeline, the typed fluent builder, and stories/draw as React components (both work via the HTML manifest). On React Native (`@nika-js/onlymap-native`): stories, draw, widgets, and overlays as native components (build native UI beside the map instead), and bare (non-Expo) React Native until its `0.2.0`. On `pick-features`: instanced (i3dm) tiles keep tile-granularity picking, and `feature-styles`' `opacity` below 1 is still being validated. On BIM: clash detection is bounding-box only (no mesh-level test, and it cannot tell a resolved penetration from a collision), there is no BCF export, no equivalent of Navisworks' Auto Reveal, and prepared tilesets converted before the `bbox*` columns existed cannot take part in a clash pass — `strength` tinting and `opacity: 0` (hide, a shader discard) work. On the measure widget's `volume` mode: the per-cell grid integration measures against the map's active terrain DEM only — measuring against an imported design surface or a previous survey (period-over-period reconciliation) and a cut/fill heat-map overlay are not implemented yet, and a snapped footprint vertex takes the matched feature's horizontal position only — its exact elevation is not threaded through (see **XY snapping** above).
|
|
331
345
|
|
|
332
346
|
## Going deeper
|
|
333
347
|
|
|
@@ -34,7 +34,11 @@ export declare const FILTER_ATTRS: Set<string>;
|
|
|
34
34
|
* `PathStyleExtension` (already bundled for DataFilterExtension), which only
|
|
35
35
|
* applies to layers that stroke a path.
|
|
36
36
|
*/
|
|
37
|
+
/** `data-emit`-style attribute name → camelCase (shared by om-map's payload reads and om-story's step parsing — both DOM-lane, one regex). */
|
|
38
|
+
export declare function kebabToCamel(name: string): string;
|
|
37
39
|
export declare const DASH_ATTRS: Set<string>;
|
|
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
|
+
export declare const CLASSIFY_ATTRS: Set<string>;
|
|
38
42
|
/** Layer types whose deck class strokes a path, so PathStyleExtension's dash takes effect (GeoJsonLayer/PolygonLayer dash their line/stroke sublayers). */
|
|
39
43
|
export declare const DASH_CAPABLE_LAYERS: Set<string>;
|
|
40
44
|
/** 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. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as ny, L as sy, M as oy, m as ay, c as ka, z as oc, a as Sd, 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, z as oc, a as Sd, 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-ESUJidEA.js";
|
|
2
2
|
const Cd = Math.PI / 180, gy = 180 / Math.PI;
|
|
3
3
|
function em(Pe, Q = 0) {
|
|
4
4
|
const me = Math.min(180, Pe) * Cd;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classified symbology (issue #12 — "categorized/graduated styling, named
|
|
3
|
+
* ramps + auto-generated legend"). The half `scale()` deliberately does NOT
|
|
4
|
+
* cover: class breaks computed FROM THE DATA. An auto-domain expression was
|
|
5
|
+
* rejected long ago as impure ("an auto-domain scale() broke the cache"), so
|
|
6
|
+
* classification lives at the layer level instead, resolved where the rows
|
|
7
|
+
* are already in hand (parse-manifest / descriptorToIR — the same "resolved
|
|
8
|
+
* once data is present" seam `highlighted-id` and the CityJSON defaults
|
|
9
|
+
* use). URL-backed layers classify on the reparse their data arrival
|
|
10
|
+
* triggers; until then the layer renders unclassified, not blank.
|
|
11
|
+
*
|
|
12
|
+
* Authoring surface (universal layer attributes, like filter-*):
|
|
13
|
+
* classify-by="magnitude" the numeric field
|
|
14
|
+
* classify-scale="quantile" quantile (default) | equal-interval | jenks
|
|
15
|
+
* classify-classes="5" 2–12, default 5
|
|
16
|
+
* classify-ramp="viridis" a named ramp below, default viridis
|
|
17
|
+
*
|
|
18
|
+
* An authored fill-color source (get-fill-color, a color shorthand, or a
|
|
19
|
+
* script-block export) always wins — classification silently defers at
|
|
20
|
+
* runtime and validation names the conflict at author time. The generated
|
|
21
|
+
* accessor is a plain function with an updateTriggers key derived from the
|
|
22
|
+
* actual computed breaks, so deck recomputes exactly when the classification
|
|
23
|
+
* genuinely changes and never otherwise; results are memoized per data
|
|
24
|
+
* reference (inline data is reference-stable since 0.6.11).
|
|
25
|
+
*/
|
|
26
|
+
import type { LayerData, LayerMeta } from "./ir";
|
|
27
|
+
import type { Shape } from "./expr";
|
|
28
|
+
/**
|
|
29
|
+
* Named ramps — standard matplotlib / ColorBrewer stop sets, the same
|
|
30
|
+
* vocabulary COGLayer's raster colormaps use where the names overlap.
|
|
31
|
+
*/
|
|
32
|
+
export declare const CLASSIFY_RAMPS: Record<string, string[]>;
|
|
33
|
+
export declare const CLASSIFY_SCALES: readonly ["quantile", "equal-interval", "jenks"];
|
|
34
|
+
export type ClassifyScale = (typeof CLASSIFY_SCALES)[number];
|
|
35
|
+
/** k colors sampled evenly along a ramp's stops (linear RGB interpolation). */
|
|
36
|
+
export declare function rampColors(name: string, k: number): string[];
|
|
37
|
+
/** k-1 ascending upper boundaries for k classes: value < b[0] → class 0, …, ≥ b[k-2] → class k-1. */
|
|
38
|
+
export declare function quantileBreaks(sorted: readonly number[], k: number): number[];
|
|
39
|
+
export declare function equalIntervalBreaks(sorted: readonly number[], k: number): number[];
|
|
40
|
+
/**
|
|
41
|
+
* Jenks natural breaks via the classic Fisher–Jenks dynamic program. O(k·n²),
|
|
42
|
+
* so inputs above 600 values are evenly strided down to 600 first — the
|
|
43
|
+
* breaks of a stride-sampled sorted vector are statistically
|
|
44
|
+
* indistinguishable for styling purposes, and this keeps a 25k-row layer's
|
|
45
|
+
* reconcile pass flat.
|
|
46
|
+
*/
|
|
47
|
+
export declare function jenksBreaks(sortedInput: readonly number[], k: number): number[];
|
|
48
|
+
export interface ClassifySpec {
|
|
49
|
+
classifyBy?: string;
|
|
50
|
+
classifyScale?: string;
|
|
51
|
+
classifyClasses?: number;
|
|
52
|
+
classifyRamp?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Computes the classification for a layer and installs it as `getFillColor`
|
|
56
|
+
* + updateTrigger + legend, shared verbatim by both front-ends. No-ops (and
|
|
57
|
+
* leaves everything untouched) when: no `classifyBy`; a fill-color source is
|
|
58
|
+
* already authored (it wins — validation names the conflict); the data
|
|
59
|
+
* hasn't arrived yet or has under two distinct numeric values (the URL case
|
|
60
|
+
* — the data-arrival reparse re-enters here with real rows).
|
|
61
|
+
*/
|
|
62
|
+
export declare function applyClassification(props: Record<string, unknown>, meta: LayerMeta, updateTriggers: Record<string, string>, spec: ClassifySpec, data: LayerData, shape: Shape, warnLabel: string): void;
|
package/dist/clip-box.d.ts
CHANGED
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Clip box (spec: issue #34 §"Cutting / Clipping", tier 2 — the geometric
|
|
3
|
-
* complement to issue #26's clip PLANE). A real oriented... well, AXIS-
|
|
4
|
-
* ALIGNED (v1 scope, confirmed explicitly — rotation is a documented
|
|
5
|
-
* follow-up, not this) 3D box: geometry outside it is discarded (or, in
|
|
6
|
-
* `highlight` mode, dimmed rather than removed — "non-destructive"), so a
|
|
7
|
-
* dense scene (a BIM model, a point cloud, a city block) can be cut open to
|
|
8
|
-
* see what's inside.
|
|
9
|
-
*
|
|
10
|
-
* Map-level scene state (spec: `<om-map clip-box-min="..." clip-box-max="..."
|
|
11
|
-
* clip-box-invert clip-box-highlight>`), same architecture as `lighting`/
|
|
12
|
-
* `terrain`: attribute-backed, undoable, live-editable, applied to every
|
|
13
|
-
* layer by default with a per-layer `clip="off"` escape hatch — see
|
|
14
|
-
* `applyClipBox`'s own doc comment for why that default (not opt-in) is
|
|
15
|
-
* the right one here specifically.
|
|
16
|
-
*
|
|
17
|
-
* Three corrections from the original design review, all reflected below:
|
|
18
|
-
* 1. "Outside the box" is `!inside` (De Morgan's law on the AND of 6
|
|
19
|
-
* half-spaces) — NOT a literal OR of 6 flipped half-space tests, which
|
|
20
|
-
* would (incorrectly) require re-deriving 6 new inequalities; negating
|
|
21
|
-
* the single boolean `inside` result is simpler and exactly equivalent.
|
|
22
|
-
* 2. Plane/box bounds are expressed in deck's COMMON SPACE (via
|
|
23
|
-
* `Layer#projectPosition`, the SAME mechanism the built-in `ClipExtension`
|
|
24
|
-
* uses for its own 2D bounds) — never raw lng/lat — so one authored box
|
|
25
|
-
* clips layers in different coordinate systems (geographic, meter-offset
|
|
26
|
-
* BIM placements, etc.) correctly.
|
|
27
|
-
* 3. Picking (including the `pickable:'3d'` depth pass) is covered for
|
|
28
|
-
* free: `discard` inside `fs:DECKGL_FILTER_COLOR` is the SAME shader
|
|
29
|
-
* stage deck's own picking pass reuses — no separate picking-specific
|
|
30
|
-
* code needed, confirmed by the built-in `ClipExtension` doing nothing
|
|
31
|
-
* extra for picking either.
|
|
32
|
-
*/
|
|
33
1
|
import { LayerExtension } from "@deck.gl/core";
|
|
34
2
|
import type { Layer } from "@deck.gl/core";
|
|
35
3
|
import type { LayerIR } from "./ir";
|
package/dist/data-layer.d.ts
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Data Layer (spec: "Module Breakdown / Data Layer").
|
|
3
|
-
* Fetches the `data` attribute URL and caches the parsed response by URL, or
|
|
4
|
-
* (Phase 3) reads inline JSON from a child `<script type="application/json">`
|
|
5
|
-
* synchronously with no fetch/cache involved. Full request-generation/
|
|
6
|
-
* AbortController handling (Q6: "Async data loading & the reconcile race") is
|
|
7
|
-
* still a minimal, safe subset here — a per-URL fetch generation so a
|
|
8
|
-
* superseded request can't clobber a newer one — not the full machinery.
|
|
9
|
-
*
|
|
10
|
-
* Columnar (spec: "Columnar / GeoArrow Ingestion"): the Data Layer is where
|
|
11
|
-
* columnar sources become `ColumnarData` — Arrow IPC files (`.arrow`,
|
|
12
|
-
* lazy-importing apache-arrow so it never weighs on the eager bundle) and
|
|
13
|
-
* column-oriented JSON (`{ columns: { field: [...] } }`, inline or fetched).
|
|
14
|
-
* Columnar data is handed to deck.gl as-is (zero row materialization on the
|
|
15
|
-
* render path); row objects are materialized lazily and memoized only when
|
|
16
|
-
* a row-consuming surface (ctx.data, picking, highlight-by-id) asks.
|
|
17
|
-
*/
|
|
18
1
|
import type { Shape, ColumnarData, LayerData } from "./ir";
|
|
19
2
|
export declare function isColumnar(data: LayerData): data is ColumnarData;
|
|
20
3
|
/** `Array` as-is, or a FeatureCollection's `.features`, or a lone object wrapped in an array. */
|
|
@@ -65,6 +65,9 @@ export declare class DrawController {
|
|
|
65
65
|
* Consumed (cleared) by the very next click regardless of whether it matched.
|
|
66
66
|
*/
|
|
67
67
|
private lastClosePos;
|
|
68
|
+
/** The previous click's coordinate + timestamp — the first half of a possible double-tap (see DOUBLE_TAP_MS). */
|
|
69
|
+
private lastTapPos;
|
|
70
|
+
private lastTapTime;
|
|
68
71
|
constructor(mapEl: Element, core: RuntimeCore);
|
|
69
72
|
/** A draw tool is active — om-map routes points here and suppresses selection. */
|
|
70
73
|
isCapturing(): boolean;
|
|
@@ -109,7 +112,7 @@ export declare class DrawController {
|
|
|
109
112
|
private ensureCommittedLayer;
|
|
110
113
|
setMode(target: string, mode: DrawMode | null): void;
|
|
111
114
|
private deactivate;
|
|
112
|
-
point(coord: [number, number] | null, kind: "click" | "hover"): void;
|
|
115
|
+
point(coord: [number, number] | null, kind: "click" | "hover", pointerType?: string): void;
|
|
113
116
|
/** Drop a queued hover-coalesced render (a following immediate render already supersedes it). */
|
|
114
117
|
private cancelHoverRaf;
|
|
115
118
|
/** `CLOSE_GUARD_PIXELS` converted to real meters at the current zoom/latitude (standard Web Mercator meters-per-pixel). */
|
package/dist/effects.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { RuntimeCore } from "./runtime-core";
|
|
|
13
13
|
export declare function traceProgress(t01: number, t0: number, t1: number): number;
|
|
14
14
|
/** Oscillates 1 → low → 1 per cycle (cosine), ending exactly at 1 for whole cycles. */
|
|
15
15
|
export declare function pulseOpacity(t01: number, cycles: number, low?: number): number;
|
|
16
|
+
export declare function prefersReducedMotion(): boolean;
|
|
16
17
|
export interface LayerEffect {
|
|
17
18
|
/** t01 ∈ [0, 1] → the plain-prop patch for this frame. */
|
|
18
19
|
frame(t01: number): Record<string, unknown>;
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <om-map> — spec: "Manifest Format / Core elements", "Architecture Layers",
|
|
3
|
-
* "Runtime Context API", "Reactivity — the watch declaration".
|
|
4
|
-
* Light DOM (spec: "DOM Model — Shadow vs. Light"): hosts the deck.gl canvas
|
|
5
|
-
* (inside an internal mount div) and the <om-layer>/<om-widget> children
|
|
6
|
-
* as normal siblings.
|
|
7
|
-
*
|
|
8
|
-
* Reconciler: full reparse per reconcile (still no diff-skipping of unchanged
|
|
9
|
-
* DOM — accessor-level memoization/fingerprinting does the real work, see
|
|
10
|
-
* attribute-resolution.ts / runtime-core.ts), microtask-batched (spec:
|
|
11
|
-
* "MutationObserver burst batching") so N mutations in one synchronous burst
|
|
12
|
-
* collapse into a single reconcile. No basemap adapter yet (Phase 6).
|
|
13
|
-
*
|
|
14
|
-
* Phase 4: also the widget pub-sub hub — maintains the live layer-IR
|
|
15
|
-
* registry (for ctx.layers/data/stats), the current selection, and notifies
|
|
16
|
-
* registered widgets per their `watch` tokens (spec: "Reactivity"). This
|
|
17
|
-
* internal registration API (registerWidgetInternal/unregisterWidgetInternal/
|
|
18
|
-
* emit) is consumed by OmWidgetElement, not part of the public package API.
|
|
19
|
-
*/
|
|
20
1
|
import { HTMLElementBase } from "../env";
|
|
21
2
|
import { type RuntimeContext } from "../ctx";
|
|
22
3
|
import { type LightingIR } from "../scene-lighting";
|
|
@@ -73,7 +54,6 @@ export declare class OmMapElement extends HTMLElementBase {
|
|
|
73
54
|
/** Dedup guard for the no-terrain-for-elevation error — same shape as `warnedApproximatePlacement`. */
|
|
74
55
|
private erroredNoTerrainForElevation;
|
|
75
56
|
private readyFired;
|
|
76
|
-
private visibleSizeChecked;
|
|
77
57
|
/** Custom-state holder for the `om-collapsed` height-floor marker — see applyHeightFloor. */
|
|
78
58
|
private internals;
|
|
79
59
|
private resolveReady;
|
|
@@ -278,7 +258,7 @@ export declare class OmMapElement extends HTMLElementBase {
|
|
|
278
258
|
/** Harness map-point injection (spec: "Consumer Testing Surface") — the
|
|
279
259
|
* same path a real deck click/hover coordinate takes, so the om-map-point
|
|
280
260
|
* event and custom capture tools are testable without a GPU. */
|
|
281
|
-
injectMapPointInternal(coordinate: [number, number] | null, kind?: "click" | "hover"): void;
|
|
261
|
+
injectMapPointInternal(coordinate: [number, number] | null, kind?: "click" | "hover", pointerType?: string): void;
|
|
282
262
|
/** Harness setView (spec: "Consumer Testing Surface") — the one path that reaches pitch/bearing. */
|
|
283
263
|
setViewInternal(partial: {
|
|
284
264
|
longitude?: number;
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <om-story> — the storyboard element (spec: "Map Stories"). A story is a
|
|
3
|
-
* time-sequenced action dispatcher: where <om-behavior> maps event →
|
|
4
|
-
* action, a story maps time → action, through the exact same action-payload
|
|
5
|
-
* contract (mapEl.emit). It owns the clock; nothing owns the story — the
|
|
6
|
-
* player widget is optional chrome that emits story-play/pause/seek.
|
|
7
|
-
*
|
|
8
|
-
* Composability guarantee (spec): steps reference layers/overlays by id and
|
|
9
|
-
* never contain them; delete the story and the map is byte-for-byte the
|
|
10
|
-
* same map.
|
|
11
|
-
*
|
|
12
|
-
* Scrub model (spec, v1): seek(T) = restore captured initial state, then
|
|
13
|
-
* re-fire the FINAL state of every step starting ≤ T (instant — payload
|
|
14
|
-
* duration overridden to 0). Step-granularity; mid-step interpolation is
|
|
15
|
-
* deferred. Initial state is captured on first play from the attributes the
|
|
16
|
-
* built-in-action steps will touch (statically computable from payloads)
|
|
17
|
-
* plus the camera; custom-action steps are replay-only (warned once).
|
|
18
|
-
*/
|
|
19
1
|
import { HTMLElementBase } from "../env";
|
|
20
2
|
export type StoryState = "idle" | "playing" | "paused" | "ended";
|
|
21
3
|
export declare class OmStoryElement extends HTMLElementBase {
|
package/dist/expr/errors.d.ts
CHANGED
|
@@ -8,3 +8,6 @@ export declare class CompileError extends Error {
|
|
|
8
8
|
readonly fix: string;
|
|
9
9
|
constructor(message: string, fix: string);
|
|
10
10
|
}
|
|
11
|
+
import type { Program } from "estree";
|
|
12
|
+
/** Shared acorn container parse for both accessor-block flavors — one grammar, one error shape; only the fix hint names the block. */
|
|
13
|
+
export declare function parseProgram(blockText: string, blockLabel: string): Program;
|
package/dist/field-access.d.ts
CHANGED
|
@@ -22,3 +22,13 @@ export declare function matchesFeatureId(row: unknown, featureId: string, shape:
|
|
|
22
22
|
* asRows view — the Tier-2 rule, stated once here instead of at each caller.
|
|
23
23
|
*/
|
|
24
24
|
export declare function findRowIndexById(data: LayerData, featureId: string, shape: Shape): number;
|
|
25
|
+
/**
|
|
26
|
+
* Shape-less named-field read: a GeoJSON Feature's field lives under
|
|
27
|
+
* `properties`, a flat row carries it directly — probe both, `in`-checked so
|
|
28
|
+
* an explicit null/undefined stored under properties still wins. For callers
|
|
29
|
+
* that have no `Shape` in hand (the Tracking layer pair); everything with a
|
|
30
|
+
* shape should use `getField`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readNamedField(row: unknown, field: string): unknown;
|
|
33
|
+
/** Recursively walks GeoJSON `coordinates` (Point/LineString/Polygon/Multi*) collecting every [lng, lat] vertex. */
|
|
34
|
+
export declare function collectCoordinates(coordinates: unknown, out: [number, number][]): void;
|
package/dist/geodesy.d.ts
CHANGED
|
@@ -23,6 +23,15 @@ export type LngLat = [number, number];
|
|
|
23
23
|
export declare function distanceMeters(a: LngLat, b: LngLat, radius?: number): number;
|
|
24
24
|
/** Total haversine length of a polyline in meters (0 for < 2 points). */
|
|
25
25
|
export declare function pathLengthMeters(points: LngLat[], radius?: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Web Mercator ground resolution — meters per screen pixel at a latitude and
|
|
28
|
+
* zoom. The one formula four controllers used to carry inline (draw close
|
|
29
|
+
* guard, clip-box handle radius, measure hover tolerance, filter histogram).
|
|
30
|
+
* `minCosLat` clamps the cosine near the poles (the clip-box gizmo needs a
|
|
31
|
+
* floor so handle hit radii stay finite above ~84°); the default 0 keeps the
|
|
32
|
+
* exact classic formula.
|
|
33
|
+
*/
|
|
34
|
+
export declare function metersPerPixel(latitude: number, zoom: number, minCosLat?: number): number;
|
|
26
35
|
export interface PathSample {
|
|
27
36
|
position: LngLat;
|
|
28
37
|
/** Cumulative distance (m) from the path's start. */
|
|
@@ -42,6 +51,8 @@ export interface PathSample {
|
|
|
42
51
|
*/
|
|
43
52
|
export declare function resamplePath(points: LngLat[], count: number): PathSample[];
|
|
44
53
|
export declare function resamplePathWithVertices(points: LngLat[], count: number): PathSample[];
|
|
54
|
+
/** Drop a trailing vertex that duplicates the first (a closed ring → open list). */
|
|
55
|
+
export declare function openRing(ring: LngLat[]): LngLat[];
|
|
45
56
|
/**
|
|
46
57
|
* Spherical polygon area in m² via the Chamberlain–Duquette line integral (the
|
|
47
58
|
* exact index form Turf's `ringArea` uses, so results match Turf's fixtures).
|
package/dist/html-data.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ interface TagData {
|
|
|
17
17
|
/** Hand-authored action list — validated against hasAction() in html-data.test.ts. */
|
|
18
18
|
export declare const BUILTIN_ACTIONS: readonly ["toggle-layer", "zoom-in", "zoom-out", "filter-layer", "highlight-feature", "fade", "pulse", "populate", "trace", "story-play", "story-pause", "story-seek", "fly-to", "zoom-to-feature", "show-overlay", "hide-overlay", "show-tooltip", "hide-tooltip", "draw-mode", "draw-commit", "draw-cancel", "draw-delete", "draw-clear", "draw-config", "draw-save", "export-region-3d", "measure-mode", "measure-clear", "measure-units", "set-basemap", "set-lighting", "set-terrain", "set-clip-box", "clip-box-edit", "set-widgets-visible", "undo", "redo"];
|
|
19
19
|
/** Hand-authored widget types — validated against the widget registry in html-data.test.ts. */
|
|
20
|
-
export declare const BUILTIN_WIDGETS: readonly ["legend", "layer-switcher", "zoom-controls", "scale-bar", "attribution", "filter", "vega-lite", "dynamic-chart", "player", "draw", "measure", "basemap-switcher", "lighting", "clip-box", "undo-redo", "widgets-toggle", "ifc-browser", "ifc-legend", "feature-inspector", "ifc-inspector", "ifc-loader", "ifc-clash"];
|
|
20
|
+
export declare const BUILTIN_WIDGETS: readonly ["legend", "layer-switcher", "zoom-controls", "scale-bar", "attribution", "filter", "vega-lite", "dynamic-chart", "player", "draw", "measure", "basemap-switcher", "lighting", "clip-box", "undo-redo", "widgets-toggle", "time-slider", "ifc-browser", "ifc-legend", "feature-inspector", "ifc-inspector", "ifc-loader", "ifc-clash"];
|
|
21
21
|
export declare function buildHtmlCustomData(): {
|
|
22
22
|
version: number;
|
|
23
23
|
tags: TagData[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ag as Be, ah as le, ai as ce, aj as De, ak as Oe, al as ke } from "./index-
|
|
1
|
+
import { ag as Be, ah as le, ai as ce, aj as De, ak as Oe, al as ke } from "./index-ESUJidEA.js";
|
|
2
2
|
import { y as ve, a as he, z as G, R as J, A as ue, C as Fe, F as je, n as xe, S as Ie, E as Ne } from "./recordbatch-Bpc0uxFn.js";
|
|
3
3
|
import { g as V, a as fe, b as Le, c as Ue, d as Me, e as qe, m as Ve } from "./table-accessors-CYWTzpQI.js";
|
|
4
4
|
import { c as $e } from "./convert-arrow-schema-DrAihRf9.js";
|
|
@@ -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-ESUJidEA.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";
|