@nika-js/onlymap 0.1.1 → 0.2.1
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/.vscode/onlymap.code-snippets +4 -4
- package/README.md +28 -6
- package/dist/attribute-resolution.d.ts +39 -0
- package/dist/{basemap-D95W0IIA.js → basemap-COurZNDH.js} +2126 -2105
- package/dist/basemap-registry.d.ts +49 -0
- package/dist/basemap.d.ts +22 -2
- package/dist/html-data.d.ts +2 -2
- package/dist/{index-Do7hmHwi.js → index-COu-3-gN.js} +1 -1
- package/dist/{index-D74olQ9w.js → index-CgyAD98B.js} +1 -1
- package/dist/{index-CU-iOTdr.js → index-CvfuISOc.js} +14602 -14137
- package/dist/{index-C9w78NS9.js → index-D-X8KPA1.js} +1 -1
- package/dist/{index-BFjXVHly.js → index-DuvXK95V.js} +2 -2
- package/dist/index.d.ts +10 -0
- package/dist/ir-diff.d.ts +16 -0
- package/dist/onlymapjs.js +29 -24
- package/dist/onlymapjs.umd.cjs +265 -259
- package/dist/programmatic.d.ts +186 -0
- package/dist/react/context.d.ts +25 -0
- package/dist/react/index.d.ts +20 -0
- package/dist/react/om-layer.d.ts +38 -0
- package/dist/react/om-map.d.ts +33 -0
- package/dist/react/om-overlay.d.ts +27 -0
- package/dist/react/om-widget.d.ts +9 -0
- package/dist/react/use-om-map.d.ts +2 -0
- package/dist/react.js +280 -0
- package/dist/runtime-core.d.ts +34 -1
- package/dist/widget-registry.d.ts +2 -0
- package/docs/3d-assets.md +74 -0
- package/docs/basemaps.md +89 -0
- package/docs/live-data.md +83 -0
- package/docs/react.md +120 -0
- package/docs/stories.md +134 -0
- package/docs/testing.md +165 -0
- package/llms.txt +8 -4
- package/onlymapjs.html-data.json +57 -1
- package/package.json +24 -2
- package/skills/onlymapjs/SKILL.md +15 -3
- package/skills/onlymapjs/references/patterns.md +2 -2
- package/skills/onlymapjs/references/react.md +68 -0
- package/skills/onlymapjs/references/syntax.md +6 -2
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
" <meta charset=\"utf-8\" />",
|
|
11
11
|
" <title>${1:My map}</title>",
|
|
12
12
|
" <script type=\"module\">",
|
|
13
|
-
" import \"
|
|
14
|
-
" import \"
|
|
13
|
+
" import \"@nika-js/onlymap\";",
|
|
14
|
+
" import \"@nika-js/onlymap/onlymapjs.css\";",
|
|
15
15
|
" </script>",
|
|
16
16
|
"</head>",
|
|
17
17
|
"<body>",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
" <meta charset=\"utf-8\" />",
|
|
56
56
|
" <title>${1:My map}</title>",
|
|
57
57
|
" <script type=\"module\">",
|
|
58
|
-
" import \"
|
|
59
|
-
" import \"
|
|
58
|
+
" import \"@nika-js/onlymap\";",
|
|
59
|
+
" import \"@nika-js/onlymap/onlymapjs.css\";",
|
|
60
60
|
" </script>",
|
|
61
61
|
"</head>",
|
|
62
62
|
"<body>",
|
package/README.md
CHANGED
|
@@ -54,9 +54,9 @@ Five elements, one rule: **attributes are kebab-case versions of deck.gl props**
|
|
|
54
54
|
|
|
55
55
|
| Element | Role |
|
|
56
56
|
|---|---|
|
|
57
|
-
| `<om-map>` | The map. `center`, `zoom`, `pitch`, `bearing`; `basemap
|
|
57
|
+
| `<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. |
|
|
58
58
|
| `<om-layer>` | Any of **33 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. `id` required; `label`/`color` feed the legend. |
|
|
59
|
-
| `<om-widget>` | UI panels. Built-ins: `legend`, `layer-switcher`, `zoom-controls`, `scale-bar`, `attribution`, `filter`, `draw`, `vega-lite` (live charts). Or write your own inline with HTML + a `<script type="om/widget">`. |
|
|
59
|
+
| `<om-widget>` | UI panels. Built-ins: `legend`, `layer-switcher`, `basemap-switcher`, `zoom-controls`, `scale-bar`, `attribution`, `filter`, `draw`, `vega-lite` (live charts). Or write your own inline with HTML + a `<script type="om/widget">`. |
|
|
60
60
|
| `<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`. `{{field}}` interpolates the picked feature, HTML-escaped by default. |
|
|
61
61
|
| `<om-behavior>` | Declarative interactions: `on="click|hover|drag|load|data-loaded"` → a named action. |
|
|
62
62
|
| `<om-story>` | A storyboard: `<om-step>` children fire actions on a timeline. Controlled by the `player` widget, behaviors, or `storyEl.play()/pause()/seek()`. |
|
|
@@ -93,7 +93,9 @@ Private endpoints: `OmMap.configureData({ headers, credentials, fetch })` — ap
|
|
|
93
93
|
|
|
94
94
|
### Interaction
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
Built-in actions wire to picks, widget buttons (`data-emit`), or script (`ctx.emit`) with one shared payload contract: `show-overlay`, `hide-overlay`, `show-tooltip`, `hide-tooltip`, `toggle-layer`, `highlight-feature`, `zoom-to-feature`, `filter-layer`, `set-basemap`, `zoom-in`, `zoom-out` — plus `OmMap.registerAction` for your own.
|
|
97
|
+
|
|
98
|
+
**Basemaps:** free presets out of the box — OpenFreeMap `liberty`/`bright`/`positron` (no key, no limits), CARTO `dark-matter`/`voyager`, classic `osm` raster, and keyed `maptiler-*` presets (MapTiler's style editor is the visual way to customize basemap JSON; keys are publishable, via `basemap-key` or `OmMap.configureBasemap`). The `basemap` attribute switches **live** — camera and layers survive — from a hand edit, the `set-basemap` action, or `<om-widget type="basemap-switcher">`. Add your own with `OmMap.registerBasemap(name, { style })`; required attribution renders automatically. Guide: [docs/basemaps.md](docs/basemaps.md).
|
|
97
99
|
|
|
98
100
|
**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.
|
|
99
101
|
|
|
@@ -105,6 +107,25 @@ GPU filtering is declarative — `filter-field="magnitude" filter-range="[4,10]"
|
|
|
105
107
|
|
|
106
108
|
Custom widget scripts receive `ctx`: layer metadata, `viewport` (bounds/zoom/project), the current `selection`, `emit()`, and data access — `ctx.data(id)`, `ctx.dataInViewport(id)`, `ctx.stats(id, field)` (count/min/max/mean/stddev/percentiles/histogram, viewport-scoped on request). Declare `watch` tokens (`data:quakes viewport selection layers`) and the runtime re-renders you only when relevant state changes. `vegaEmbed` and `d3` are available as globals for charts.
|
|
107
109
|
|
|
110
|
+
## React
|
|
111
|
+
|
|
112
|
+
The same engine, as real components — `@nika-js/onlymap/react` (React ≥ 18, optional peer). No `om-*` elements are rendered, so React and the library never fight over the DOM: components feed a typed programmatic front-end that produces the same layer IR the HTML manifest does. Accessors are plain functions (no expression language), interactions are event handlers, and `useOmMap()` is the widget `ctx` contract as a fully-typed hook:
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
import { OmMap, OmLayer, OmWidget, OmOverlay, useOmMap } from "@nika-js/onlymap/react";
|
|
116
|
+
|
|
117
|
+
<OmMap center={[-119, 36]} zoom={5} basemap="maplibre">
|
|
118
|
+
<OmLayer id="quakes" type="ScatterplotLayer" data={features} pickable
|
|
119
|
+
getPosition={d => [d.lon, d.lat]}
|
|
120
|
+
getFillColor={d => (d.mag >= 6 ? [214, 40, 40] : [252, 191, 73])}
|
|
121
|
+
onClick={sel => setSelected(sel.object)} />
|
|
122
|
+
<OmWidget position="top-left"><StatsPanel /></OmWidget>
|
|
123
|
+
<OmOverlay anchorFrom="selection">{sel => sel && <Card feature={sel.object} />}</OmOverlay>
|
|
124
|
+
</OmMap>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`<OmOverlay>` manages projection, per-frame tracking, and off-screen culling for you; `<OmMap headless>` makes the whole tree testable in jsdom/happy-dom. Full guide: [docs/react.md](docs/react.md).
|
|
128
|
+
|
|
108
129
|
## Editor IntelliSense
|
|
109
130
|
|
|
110
131
|
`onlymapjs.html-data.json` (generated from the layer registry — `npm run gen:html-data`) gives autocomplete and hover docs for every `om-*` element and attribute in VS Code and any editor speaking the [html-customData](https://github.com/microsoft/vscode-custom-data) format:
|
|
@@ -171,18 +192,19 @@ Plus `OmMap.snapshotIR(html)` to lock down what a manifest *means* in a snapshot
|
|
|
171
192
|
|
|
172
193
|
## Programmatic surface
|
|
173
194
|
|
|
174
|
-
- **`OmMap.*`** — `validate`, `snapshotIR`, `registerLayer`, `registerWidget`, `registerAction`, `registerSource`, `registerFormat`, `configureData`, `getLayerSchema`
|
|
195
|
+
- **`OmMap.*`** — `validate`, `snapshotIR`, `registerLayer`, `registerWidget`, `registerAction`, `registerSource`, `registerFormat`, `registerBasemap`, `configureBasemap`, `configureData`, `getLayerSchema`
|
|
175
196
|
- **On a `<om-map>` element** — `ready` (promise), `flyTo(coords, zoom?)`, `setLayerVisible(id, bool)`, `getLayers()`, `emit(action, payload)`; `document.querySelector("om-map")` is fully typed
|
|
197
|
+
- **`MapController`** — the framework-grade programmatic front-end (typed `LayerDescriptor`s → the same reconcile core, no DOM manifest): `setLayers`, `watch`, `emit`, camera methods, `injectPick`, `ready`. The React adapter rides it; usable directly from vanilla TS or other frameworks
|
|
176
198
|
- **Testing** — `mountForTest`, and imports are SSR-safe (importing in Node/jsdom never touches browser globals)
|
|
177
199
|
|
|
178
200
|
## Not implemented yet (honestly)
|
|
179
201
|
|
|
180
|
-
Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, multi-field filters, `dblclick` behaviors, the `transform` data pipeline, and
|
|
202
|
+
Mapbox GL basemaps, depth-interleaved 3D compositing, globe projection, SSE transport, multi-field filters, `dblclick` behaviors, the `transform` data pipeline, the typed fluent builder, and stories/draw as React components (both work via the HTML manifest).
|
|
181
203
|
|
|
182
204
|
## Going deeper
|
|
183
205
|
|
|
184
206
|
| | |
|
|
185
207
|
|---|---|
|
|
186
|
-
| [docs/testing.md](docs/testing.md) · [docs/live-data.md](docs/live-data.md) · [docs/3d-assets.md](docs/3d-assets.md) · [docs/stories.md](docs/stories.md) | Consumer guides |
|
|
208
|
+
| [docs/react.md](docs/react.md) · [docs/basemaps.md](docs/basemaps.md) · [docs/testing.md](docs/testing.md) · [docs/live-data.md](docs/live-data.md) · [docs/3d-assets.md](docs/3d-assets.md) · [docs/stories.md](docs/stories.md) | Consumer guides |
|
|
187
209
|
| [llms.txt](llms.txt) | The agent-facing quick reference |
|
|
188
210
|
| `skills/onlymapjs` | Installable LLM skill for OnlyMapJS authoring |
|
|
@@ -24,6 +24,45 @@ export declare const RESERVED_ATTRS: Set<string>;
|
|
|
24
24
|
* dimensions" case is a documented future extension.
|
|
25
25
|
*/
|
|
26
26
|
export declare const FILTER_ATTRS: Set<string>;
|
|
27
|
+
/** Already-coerced filter declaration — attribute strings (DOM front-end) or typed values (programmatic front-end). */
|
|
28
|
+
export interface LayerFilterSpec {
|
|
29
|
+
filterField?: string;
|
|
30
|
+
filterRange?: [number, number];
|
|
31
|
+
filterSoftRange?: [number, number];
|
|
32
|
+
filterCategoryField?: string;
|
|
33
|
+
filterCategories?: unknown[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* GPU filter wiring (spec: "Filtering"), shared by both front-ends (HU2).
|
|
37
|
+
* `filterRange` is a plain prop (not an accessor): the filter-layer action
|
|
38
|
+
* just rewrites its attribute, which flows through the normal reconcile ->
|
|
39
|
+
* deck.gl setProps() diff as a cheap uniform update, never touching
|
|
40
|
+
* updateTriggers.
|
|
41
|
+
*
|
|
42
|
+
* EVERY layer mounts the extension at birth, filtered or not: adding or
|
|
43
|
+
* removing an extension on a LIVE layer recompiles shaders and corrupts
|
|
44
|
+
* attribute state (the per-feature-trace washed-out-fill bug), while an
|
|
45
|
+
* idle numeric slot is free — deck's default getFilterValue is the
|
|
46
|
+
* CONSTANT 0 (no attribute buffer) inside the default filterRange
|
|
47
|
+
* [-1, 1], so nothing is culled. A later filter-layer action then only
|
|
48
|
+
* swaps accessor + range props on the same shaders. The category slot is
|
|
49
|
+
* NOT pre-mounted: an idle categorySize binds a uint attribute against a
|
|
50
|
+
* float constant (GL_INVALID_OPERATION in real WebGL), so declaring a
|
|
51
|
+
* category filter re-mounts the extension — churn accepted for the rare
|
|
52
|
+
* case, never for the common numeric one.
|
|
53
|
+
*
|
|
54
|
+
* The unfiltered baseline is a FUNCTION accessor (a buffer of zeros, 4
|
|
55
|
+
* bytes/row) plus a baseline trigger — never deck's constant-0 default.
|
|
56
|
+
* Two empirically-found deck behaviors force this: trigger keys absent
|
|
57
|
+
* from the NEW props aren't diffed (a cleared patch would keep its stale
|
|
58
|
+
* buffer), and a buffer→constant accessor transition doesn't rebind the
|
|
59
|
+
* vertex attribute (the attribute state SAYS constant 0, the GPU still
|
|
60
|
+
* draws the old buffer). Function→function with a trigger change is the
|
|
61
|
+
* one transition that recomputes reliably, so every state a layer can
|
|
62
|
+
* reach — unfiltered, authored filter, runtime populate sweep — is
|
|
63
|
+
* buffer-backed.
|
|
64
|
+
*/
|
|
65
|
+
export declare function applyFilterWiring(props: Record<string, unknown>, updateTriggers: Record<string, string>, shape: Shape, spec: LayerFilterSpec, warnLabel: string): LayerFilter | undefined;
|
|
27
66
|
/**
|
|
28
67
|
* Standard global HTML attributes an author (or the library itself, e.g.
|
|
29
68
|
* OmLayerElement setting `style.display = "none"`) may set for reasons
|