@nika-js/onlymap 0.5.3 → 0.5.7
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/README.md +20 -7
- package/THIRD-PARTY-LICENSES.md +120 -0
- package/dist/{Arrow.dom-BNjbQ9jb.js → Arrow.dom-BFGShwSA.js} +854 -1427
- package/dist/{LercDecode.es-S6KKhkuA.js → LercDecode.es-Bp2rG98n.js} +1 -1
- package/dist/{basemap-BSCq9hHZ.js → basemap-CfOA0HWY.js} +1 -1
- package/dist/builder-CqJZRFaq.js +580 -0
- package/dist/data-layer.d.ts +4 -0
- package/dist/date-format.d.ts +18 -0
- package/dist/flatgeobuf-Cx0IwxhV.js +6332 -0
- package/dist/full.esm-Cl_Dig1y.js +1467 -0
- package/dist/geoparquet-kW7KUrwB.js +35 -0
- package/dist/geoparquet.d.ts +33 -0
- package/dist/image-overlay.d.ts +83 -0
- package/dist/{index-BCgjJcZn.js → index-BLy1eTWe.js} +1 -1
- package/dist/index-BYbMtNVH.js +2301 -0
- package/dist/{index-BoAq5XsU.js → index-CUKgoX_E.js} +13291 -12728
- package/dist/index-CgPV7QlM.js +4019 -0
- package/dist/{index-D1swbykc.js → index-CnY_rdB8.js} +1 -1
- package/dist/{index-DfNGlG_k.js → index-MRS7UAHr.js} +1 -1
- package/dist/{index-BTcRCrfX.js → index-wZ6n6ggy.js} +2 -2
- package/dist/index.d.ts +5 -1
- package/dist/ir-snapshot.d.ts +3 -1
- package/dist/ir.d.ts +18 -0
- package/dist/layer-registry.d.ts +2 -0
- package/dist/{lerc-n0GaWEmL.js → lerc-DWbkmLYR.js} +2 -2
- package/dist/onlymap.standalone.js +59664 -44945
- package/dist/onlymapjs.js +76 -74
- package/dist/{raster-DO-Ex2Lb.js → raster-5jEwGISN.js} +2 -2
- package/dist/validation.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/docs/3d-assets.md +1 -1
- package/docs/image-overlays.md +75 -0
- package/llms.txt +7 -4
- package/onlymapjs.html-data.json +147 -86
- package/package.json +5 -1
- package/skills/onlymapjs/SKILL.md +4 -1
- package/skills/onlymapjs/references/syntax.md +120 -19
- package/skills/onlymapjs/references/testing.md +11 -2
|
@@ -16,8 +16,8 @@ Vite/npm project:
|
|
|
16
16
|
Static CDN page (raw-file CDNs only — unpkg/jsDelivr; never esm.sh or another rebundling CDN, which duplicates the WebGL runtime and breaks layer shaders):
|
|
17
17
|
|
|
18
18
|
```html
|
|
19
|
-
<link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap@0.5.
|
|
20
|
-
<script type="module" src="https://unpkg.com/@nika-js/onlymap@0.5.
|
|
19
|
+
<link rel="stylesheet" href="https://unpkg.com/@nika-js/onlymap@0.5.7/dist/onlymapjs.css">
|
|
20
|
+
<script type="module" src="https://unpkg.com/@nika-js/onlymap@0.5.7"></script>
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Always include `onlymapjs.css` — it carries the MapLibre basemap styles and the no-JS fallback rules (`<om-fallback>` / default banner). For the fallback to work in script-disabled previews it must load without JavaScript: a real `<link rel="stylesheet">` or inlined `<style>` on no-build pages (a bundler-emitted stylesheet is fine in npm projects).
|
|
@@ -81,10 +81,21 @@ get-position="[$lon, $lat]"
|
|
|
81
81
|
get-radius="$population * 0.001"
|
|
82
82
|
get-fill-color="$value > 100 ? [255,0,0] : [0,128,255]"
|
|
83
83
|
get-fill-color="scale($depth, sequential, ['#ffffcc','#800026'], domain=[0,700])"
|
|
84
|
+
get-text="formatDate($time, 'datetime', 'UTC')"
|
|
84
85
|
```
|
|
85
86
|
|
|
86
87
|
`$field` works on flat rows, GeoJSON properties, columnar JSON, CSV/TSV columns, and Arrow point columns.
|
|
87
88
|
|
|
89
|
+
Date formatting is a safe built-in rather than an opt-in to arbitrary JavaScript:
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
get-text="formatDate($time)"
|
|
93
|
+
get-text="formatDate($time, 'date')"
|
|
94
|
+
get-text="formatDate($time, 'datetime', 'Asia/Singapore')"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`formatDate(value, style?, timeZone?)` accepts epoch-millisecond numbers/numeric strings or ISO date strings. Numeric values are always milliseconds—multiply Unix seconds by 1000 before formatting. Styles are `date`, `datetime` (default), `time`, and `iso`; the default time zone is `UTC`, while `local` opts into the viewer's zone and IANA names select a specific zone. Invalid values produce an empty string. Restricted expressions still reject `new Date()`, `Intl`, and instance-method calls.
|
|
98
|
+
|
|
88
99
|
Smart shorthands:
|
|
89
100
|
|
|
90
101
|
- `color="#1f9e89"` sets a constant `getFillColor` when no explicit `get-fill-color` exists, and always feeds the legend swatch.
|
|
@@ -102,13 +113,24 @@ Filtering:
|
|
|
102
113
|
filter-field="magnitude" filter-range="[4, 10]"
|
|
103
114
|
```
|
|
104
115
|
|
|
116
|
+
For an epoch-millisecond filter, format the built-in widget's numeric labels declaratively:
|
|
117
|
+
|
|
118
|
+
```html
|
|
119
|
+
<om-layer id="quakes" type="GeoJsonLayer" data="./quakes.geojson"
|
|
120
|
+
filter-field="time" filter-range="[1782889284760, 1785480717910]"></om-layer>
|
|
121
|
+
<om-widget type="filter" layer="quakes" field="time"
|
|
122
|
+
format="date" date-style="datetime" time-zone="UTC"></om-widget>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`format` is `number` (default) or `date`. With `format="date"`, `date-style` uses the same four styles as `formatDate()` and `time-zone` defaults to `UTC`.
|
|
126
|
+
|
|
105
127
|
|
|
106
128
|
|
|
107
129
|
### Built-In Layer Types
|
|
108
130
|
|
|
109
131
|
Use the `type` value exactly:
|
|
110
132
|
|
|
111
|
-
`A5Layer`, `ArcLayer`, `BitmapLayer`, `COGLayer`, `ColumnLayer`, `ContourLayer`, `GeoJsonLayer`, `GeohashLayer`, `GreatCircleLayer`, `GridCellLayer`, `GridLayer`, `H3ClusterLayer`, `H3HexagonLayer`, `HeatmapLayer`, `HexagonLayer`, `IconLayer`, `LineLayer`, `MVTLayer`, `PathLayer`, `PointCloudLayer`, `PolygonLayer`, `PopupLayer`, `QuadkeyLayer`, `S2Layer`, `ScatterplotLayer`, `ScenegraphLayer`, `ScreenGridLayer`, `SimpleMeshLayer`, `SolidPolygonLayer`, `TerrainLayer`, `TextLayer`, `Tile3DLayer`, `TileLayer`, `TripsLayer`.
|
|
133
|
+
`A5Layer`, `ArcLayer`, `BitmapLayer`, `COGLayer`, `ColumnLayer`, `ContourLayer`, `GeoJsonLayer`, `GeohashLayer`, `GreatCircleLayer`, `GridCellLayer`, `GridLayer`, `H3ClusterLayer`, `H3HexagonLayer`, `HeatmapLayer`, `HexagonLayer`, `IconLayer`, `ImageOverlay`, `LineLayer`, `MVTLayer`, `PathLayer`, `PointCloudLayer`, `PolygonLayer`, `PopupLayer`, `QuadkeyLayer`, `S2Layer`, `ScatterplotLayer`, `ScenegraphLayer`, `ScreenGridLayer`, `SimpleMeshLayer`, `SolidPolygonLayer`, `TerrainLayer`, `TextLayer`, `Tile3DLayer`, `TileLayer`, `TripsLayer`.
|
|
112
134
|
|
|
113
135
|
Common choices:
|
|
114
136
|
|
|
@@ -119,6 +141,7 @@ Common choices:
|
|
|
119
141
|
- Tiles: `TileLayer`, `MVTLayer`, `Tile3DLayer`.
|
|
120
142
|
- 3D models: `ScenegraphLayer`, `SimpleMeshLayer`, `PointCloudLayer`, `Tile3DLayer`.
|
|
121
143
|
- GeoTIFF/COG rasters: `COGLayer`.
|
|
144
|
+
- Geotagged drone JPEGs: `ImageOverlay`.
|
|
122
145
|
|
|
123
146
|
|
|
124
147
|
|
|
@@ -137,6 +160,23 @@ Common choices:
|
|
|
137
160
|
- Plain 8-bit RGB COGs (satellite truecolor) need no styling attributes at all.
|
|
138
161
|
- Restretch/recolor (min/max/colormap edits) are GPU uniform updates — tiles are not refetched. The legend widget renders the colormap ramp automatically when `colormap` + `min`/`max` are authored.
|
|
139
162
|
|
|
163
|
+
### ImageOverlay (drone JPEG)
|
|
164
|
+
|
|
165
|
+
```html
|
|
166
|
+
<om-layer id="photo" type="ImageOverlay"
|
|
167
|
+
src="./DJI_0123.jpg" georeference="exif"
|
|
168
|
+
opacity="0.8"></om-layer>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- `src` (required) — a JPEG with GPS/relative-altitude/camera/focal-length EXIF and DJI gimbal XMP.
|
|
172
|
+
- `georeference="exif"` — fetches through `OmMap.configureData`, computes a flat-ground WGS84 footprint, and bakes yaw/roll into the pixels. `map.ready` waits for it.
|
|
173
|
+
- Verified camera paths include DJI FC300S and M30T, including M30T JPEGs carrying a 180° gimbal-roll correction.
|
|
174
|
+
- Unknown camera: supply `sensor-width-mm` + `sensor-height-mm` together. If EXIF lacks focal length, also supply `focal-length-mm`. Values are physical millimetres and must be positive.
|
|
175
|
+
- Persisted/preprocessed form: omit `georeference` and set `bounds="[west,south,east,north]"`; `src` may be the processed PNG. Optional JSON `metadata` passes through. Explicit bounds perform no EXIF fetch.
|
|
176
|
+
- `depth-test` defaults false. `opacity`, `visible`, and `pickable` behave like other layers.
|
|
177
|
+
- The public `await OmMap.resolveImageOverlay(fileOrUrl, options?)` returns `{image, bounds, metadata}` for upload/persistence.
|
|
178
|
+
- Visualization-grade only: no terrain, lens-distortion, calibration, or perspective-correct four-corner orthorectification. Use `COGLayer` for large orthomosaics.
|
|
179
|
+
|
|
140
180
|
External layer classes become manifest types via `OmMap.registerLayer({type, deckClass, props})`. Build them on `@nika-js/onlymap/deck` (the bundled `CompositeLayer`/`TileLayer`/… re-exports — a separately-installed deck.gl is a different class hierarchy and breaks in the renderer); function-valued props ride the subclass's `static defaultProps`; register at module top level before the manifest mounts. Full recipe: docs/custom-layers.md.
|
|
141
181
|
|
|
142
182
|
### Data Sources
|
|
@@ -151,6 +191,9 @@ External layer classes become manifest types via `OmMap.registerLayer({type, dec
|
|
|
151
191
|
| Arrow / GeoArrow IPC | `data="./big.arrow"` | Points stay columnar; lines/polygons become GeoJSON features. |
|
|
152
192
|
| Shapefile | `data="./countries.shp"` | Loads sidecars and joins `.dbf` attributes. |
|
|
153
193
|
| KML | `data="./tour.kml"` | Placemarks become GeoJSON features. |
|
|
194
|
+
| GPX | `data="./hike.gpx"` (opt. `#waypoints`/`#tracks`/`#routes`) | Waypoints/tracks/routes → GeoJSON features, each tagged `_gpxKind`; a URL fragment selects one part (no fragment = all). |
|
|
195
|
+
| FlatGeobuf | `data="./cities.fgb"` | Cloud-native binary vector — whole-file decode to GeoJSON features (bbox-streaming is a later phase). |
|
|
196
|
+
| GeoParquet | `data="./data.parquet"` (or `.geoparquet`) | Cloud-native columnar vector — all-Point files stay columnar, lines/polygons become GeoJSON features; needs the `geo` metadata (WKB geometry) and CRS84/EPSG:4326 (a projected CRS errors — reproject first). |
|
|
154
197
|
| CityJSON | `data="./tile.city.json"` | 3D city models → extruded footprints, or `?om-surfaces=1` for real per-face roof geometry; see below. |
|
|
155
198
|
| CityJSONSeq | `data="./tile.city.jsonl"` | Same, streamed line by line as it downloads. |
|
|
156
199
|
| WebSocket | `data="wss://feed" key="id" flush="250ms" source="decoder"` | Upsert-by-key stream. |
|
|
@@ -296,11 +339,30 @@ Examples:
|
|
|
296
339
|
```html
|
|
297
340
|
<om-widget type="legend" position="bottom-right" title="Layers" interactive></om-widget>
|
|
298
341
|
<om-widget type="filter" layer="quakes" field="magnitude" position="top-left"></om-widget>
|
|
342
|
+
<om-widget type="filter" layer="quakes" field="time" format="date"
|
|
343
|
+
date-style="datetime" time-zone="UTC" position="bottom-center"></om-widget>
|
|
299
344
|
<om-widget type="draw" target="sketch" modes="point line polygon" save="both"></om-widget>
|
|
300
345
|
<om-widget type="basemap-switcher" options="positron dark-matter liberty osm" position="top-right"></om-widget>
|
|
301
346
|
```
|
|
302
347
|
|
|
303
|
-
Custom
|
|
348
|
+
### Custom widgets & event emission
|
|
349
|
+
|
|
350
|
+
**Reach for a built-in first.** A plain value/time slider is a built-in:
|
|
351
|
+
`<om-widget type="filter" layer="quakes" field="time" format="date">` — it
|
|
352
|
+
renders readable date labels AND wires the `filter-layer` action for you (pair
|
|
353
|
+
it with the layer's `filter-field`). Author a custom widget ONLY for bespoke UI
|
|
354
|
+
or logic the built-ins don't cover — most "it looked right but didn't work"
|
|
355
|
+
widgets should have been a `type="filter"`/`legend`/`vega-lite` built-in.
|
|
356
|
+
|
|
357
|
+
A custom widget is an `<om-widget>` with **no `type`** plus inline HTML and a
|
|
358
|
+
`<script type="om/widget">` block. The script is full JS, evaluated ONCE at
|
|
359
|
+
connect with `this` bound to the `<om-widget>` element: set `this.watch` (a
|
|
360
|
+
list of re-render triggers) and `this.render = (ctx) => {…}`. `vegaEmbed`/`d3`
|
|
361
|
+
are available. Content renders in shadow DOM — reach it with `this.$(selector)`
|
|
362
|
+
and `this.root`.
|
|
363
|
+
|
|
364
|
+
**Read map state** through `ctx` (the `render` argument), re-rendering when a
|
|
365
|
+
watched token fires:
|
|
304
366
|
|
|
305
367
|
```html
|
|
306
368
|
<om-widget position="top-left">
|
|
@@ -315,20 +377,60 @@ Custom widget:
|
|
|
315
377
|
</om-widget>
|
|
316
378
|
```
|
|
317
379
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
- `
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
380
|
+
- `ctx.layers`, `ctx.data(id)`, `ctx.dataInViewport(id)`,
|
|
381
|
+
`ctx.stats(id, field, { scope: "viewport" })`, `ctx.selection`,
|
|
382
|
+
`ctx.viewport`, `ctx.history` (`{ canUndo, canRedo }`).
|
|
383
|
+
- Watch tokens: `data:<layerId>`, `viewport`, `selection`, `layers` (add/remove,
|
|
384
|
+
visibility, filter changes), `basemap`, `lighting`, `terrain`, `history`,
|
|
385
|
+
`widgets` (`widgets-hidden` hide-all toggle).
|
|
386
|
+
|
|
387
|
+
**Drive the map — the emission contract.** This is the part authors get wrong.
|
|
388
|
+
A widget NEVER mutates the map directly and NEVER dispatches its own
|
|
389
|
+
`CustomEvent` hoping the map listens. It **emits a registered action**, exactly
|
|
390
|
+
two ways:
|
|
391
|
+
|
|
392
|
+
1. **Declarative `data-emit`** (no script): `data-emit="<action>"` + `data-*`
|
|
393
|
+
payload keys on an element. Fires on **click** (non-form elements) or
|
|
394
|
+
**change** (form controls — `input`/`select`/`textarea`, whose `.value` is
|
|
395
|
+
auto-merged into the payload). `data-*` keys camelCase (`data-feature-id` →
|
|
396
|
+
`featureId`) and arrive as **strings** — fine for `toggle-layer`/`fly-to`,
|
|
397
|
+
but a numeric/array payload (a slider's `range: [min, max]`) needs `ctx.emit`.
|
|
398
|
+
```html
|
|
399
|
+
<button data-emit="toggle-layer" data-layer="quakes">Toggle quakes</button>
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
2. **Programmatic `ctx.emit(action, payload)`** — for typed payloads. Wire it
|
|
403
|
+
INSIDE `render` so `ctx` is in scope, assigning `.oninput`/`.onclick`
|
|
404
|
+
(idempotent across re-renders; prefer over `addEventListener`, which stacks a
|
|
405
|
+
fresh listener every render):
|
|
406
|
+
```html
|
|
407
|
+
<om-widget position="bottom-center">
|
|
408
|
+
<input id="day" type="range" min="1" max="14" step="1" value="1">
|
|
409
|
+
<script type="om/widget">
|
|
410
|
+
this.render = (ctx) => {
|
|
411
|
+
this.$("#day").oninput = (e) => {
|
|
412
|
+
const d = Number(e.target.value);
|
|
413
|
+
ctx.emit("filter-layer", { layer: "quakes", field: "day", range: [d, d] });
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
</script>
|
|
417
|
+
</om-widget>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**NEVER inline handlers** (`onclick="…"`, `oninput="ctx.emit(…)"`): `ctx` is not
|
|
421
|
+
a global, they execute in page scope, and CSP blocks them — the widget looks
|
|
422
|
+
right and silently emits nothing. This is the #1 custom-widget failure, and
|
|
423
|
+
validation errors on it.
|
|
424
|
+
|
|
425
|
+
**Actions a widget can emit** (payload keys): `filter-layer`
|
|
426
|
+
`{layer, field?, range:[min,max]}` (value/time sliders), `toggle-layer`
|
|
427
|
+
`{layer, visible?}`, `fly-to` `{center:[lng,lat], zoom?, pitch?, bearing?,
|
|
428
|
+
duration?}`, `zoom-to-feature` `{layer, featureId, duration?}`, `set-basemap`
|
|
429
|
+
`{basemap}`, `set-lighting`/`set-terrain`, `highlight-feature`
|
|
430
|
+
`{layer, featureId}`, `show-overlay`/`hide-overlay` `{target}`,
|
|
431
|
+
`story-play`/`story-pause`/`story-seek` `{story, t?}`, `undo`/`redo`,
|
|
432
|
+
`zoom-in`/`zoom-out`, `set-widgets-visible` `{visible}`. Register your own with
|
|
433
|
+
`OmMap.registerAction(name, (payload, mapEl) => …)`.
|
|
332
434
|
|
|
333
435
|
### `<om-overlay>`
|
|
334
436
|
|
|
@@ -494,4 +596,3 @@ For 3D Tiles LOD/refinement experiments, use:
|
|
|
494
596
|
maximum-memory-usage="256"
|
|
495
597
|
view-distance-scale="0.85"></om-layer>
|
|
496
598
|
```
|
|
497
|
-
|
|
@@ -10,11 +10,20 @@ Use `OmMap.validate(htmlString)` before finalizing agent-written maps.
|
|
|
10
10
|
import { OmMap } from "@nika-js/onlymap";
|
|
11
11
|
|
|
12
12
|
const result = OmMap.validate(html);
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// `valid` reflects ERRORS ONLY. Warnings (e.g. `Unknown attribute "get-radius"
|
|
14
|
+
// on GeoJsonLayer — likely a typo`) mean a prop is being silently dropped and
|
|
15
|
+
// the layer renders wrong-but-"valid", so act on BOTH lists — never stop at
|
|
16
|
+
// `valid: true`.
|
|
17
|
+
for (const entry of [...result.errors, ...result.warnings]) {
|
|
18
|
+
console.log(entry.severity, entry.attribute, entry.message, "→", entry.fix);
|
|
15
19
|
}
|
|
16
20
|
```
|
|
17
21
|
|
|
22
|
+
An `Unknown attribute` warning is usually a wrong-for-this-layer prop — check
|
|
23
|
+
`onlymapjs.html-data.json` for the layer's real attributes (e.g. `GeoJsonLayer`
|
|
24
|
+
points use `get-point-radius`/`point-radius-units`, not `ScatterplotLayer`'s
|
|
25
|
+
`get-radius`/`radius-units`).
|
|
26
|
+
|
|
18
27
|
Errors and warnings have:
|
|
19
28
|
|
|
20
29
|
```ts
|