@nika-js/onlymap 0.2.0 → 0.2.2
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 +23 -0
- package/README.md +10 -7
- package/dist/{basemap-C0RKcLaL.js → basemap-Bn4TmZtQ.js} +2126 -2105
- package/dist/basemap-registry.d.ts +49 -0
- package/dist/basemap.d.ts +22 -2
- package/dist/elements/om-fallback.d.ts +22 -0
- package/dist/html-data.d.ts +2 -2
- package/dist/{index-CZf9WlZe.js → index-3UyMg0Md.js} +1 -1
- package/dist/{index-GTGi85ZO.js → index-BZs_x9Dx.js} +2 -2
- package/dist/{index-BDJ9hHXv.js → index-D2zVsZ79.js} +1 -1
- package/dist/{index-DeEur5Xk.js → index-DSjndBOf.js} +1 -1
- package/dist/{index-DnvxPnDF.js → index-oE1Kouy1.js} +11790 -11574
- package/dist/index.d.ts +7 -0
- package/dist/onlymapjs.css +1 -1
- package/dist/onlymapjs.js +20 -17
- package/dist/onlymapjs.umd.cjs +277 -271
- package/dist/programmatic.d.ts +11 -1
- package/dist/react/om-map.d.ts +5 -1
- package/dist/react.js +136 -128
- package/dist/runtime-core.d.ts +34 -1
- package/dist/widget-registry.d.ts +2 -0
- package/docs/basemaps.md +89 -0
- package/docs/react.md +1 -1
- package/llms.txt +4 -3
- package/onlymapjs.html-data.json +69 -2
- package/package.json +2 -2
- package/skills/onlymapjs/SKILL.md +17 -2
- package/skills/onlymapjs/references/patterns.md +6 -0
- package/skills/onlymapjs/references/react.md +68 -0
- package/skills/onlymapjs/references/syntax.md +27 -3
package/onlymapjs.html-data.json
CHANGED
|
@@ -23,10 +23,53 @@
|
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"name": "basemap",
|
|
26
|
-
"description": "Basemap
|
|
26
|
+
"description": "Basemap: a registered preset name, \"maplibre\" (demo style), a style URL, or \"none\" (standalone canvas).",
|
|
27
27
|
"values": [
|
|
28
28
|
{
|
|
29
29
|
"name": "maplibre"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "none"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "liberty"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "bright"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "positron"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "dark-matter"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "voyager"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "osm"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "maptiler-streets"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "maptiler-dataviz"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "maptiler-satellite"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "basemap-key",
|
|
65
|
+
"description": "Provider API key for keyed basemap presets (maptiler-*) — publishable origin-restricted key; or call OmMap.configureBasemap once."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "attribution",
|
|
69
|
+
"description": "Set \"false\" to opt out of the compact attribution control shown with basemaps.",
|
|
70
|
+
"values": [
|
|
71
|
+
{
|
|
72
|
+
"name": "false"
|
|
30
73
|
}
|
|
31
74
|
]
|
|
32
75
|
},
|
|
@@ -50,7 +93,7 @@
|
|
|
50
93
|
"references": [
|
|
51
94
|
{
|
|
52
95
|
"name": "README",
|
|
53
|
-
"url": "https://github.com/NikaGeospatial/onlymapjs/blob/main/
|
|
96
|
+
"url": "https://github.com/NikaGeospatial/onlymapjs/blob/main/README.md"
|
|
54
97
|
}
|
|
55
98
|
]
|
|
56
99
|
},
|
|
@@ -1251,6 +1294,17 @@
|
|
|
1251
1294
|
}
|
|
1252
1295
|
]
|
|
1253
1296
|
},
|
|
1297
|
+
{
|
|
1298
|
+
"name": "om-fallback",
|
|
1299
|
+
"description": "Static fallback shown only when the library never boots — JS-disabled contexts like chat-app/email file previews (iOS QuickLook), file managers, sandboxed webviews. Direct child of <om-map>; hidden automatically once the map upgrades. Good practice on any page that may be shared as a file. Without one, the stylesheet shows a text-only default banner. Requires onlymapjs.css to load without JS (link tag / bundled / inlined).",
|
|
1300
|
+
"attributes": [],
|
|
1301
|
+
"references": [
|
|
1302
|
+
{
|
|
1303
|
+
"name": "README",
|
|
1304
|
+
"url": "https://github.com/NikaGeospatial/onlymapjs/blob/main/README.md"
|
|
1305
|
+
}
|
|
1306
|
+
]
|
|
1307
|
+
},
|
|
1254
1308
|
{
|
|
1255
1309
|
"name": "om-behavior",
|
|
1256
1310
|
"description": "Declarative event → action wiring. Every other attribute becomes a payload key (kebab→camel).",
|
|
@@ -1358,6 +1412,9 @@
|
|
|
1358
1412
|
},
|
|
1359
1413
|
{
|
|
1360
1414
|
"name": "draw-save"
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
"name": "set-basemap"
|
|
1361
1418
|
}
|
|
1362
1419
|
]
|
|
1363
1420
|
},
|
|
@@ -1405,6 +1462,9 @@
|
|
|
1405
1462
|
},
|
|
1406
1463
|
{
|
|
1407
1464
|
"name": "draw"
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
"name": "basemap-switcher"
|
|
1408
1468
|
}
|
|
1409
1469
|
]
|
|
1410
1470
|
},
|
|
@@ -1483,6 +1543,10 @@
|
|
|
1483
1543
|
"name": "autosave",
|
|
1484
1544
|
"description": "Draw widget: localStorage key — mirrors the sketch and restores it on reload."
|
|
1485
1545
|
},
|
|
1546
|
+
{
|
|
1547
|
+
"name": "options",
|
|
1548
|
+
"description": "Basemap-switcher: space-separated preset names to offer (default: every keyless registered preset)."
|
|
1549
|
+
},
|
|
1486
1550
|
{
|
|
1487
1551
|
"name": "title",
|
|
1488
1552
|
"description": "Widget heading."
|
|
@@ -1613,6 +1677,9 @@
|
|
|
1613
1677
|
},
|
|
1614
1678
|
{
|
|
1615
1679
|
"name": "draw-save"
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
"name": "set-basemap"
|
|
1616
1683
|
}
|
|
1617
1684
|
]
|
|
1618
1685
|
},
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nika-js/onlymap",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Interactive WebGL maps from declarative HTML — a custom-element manifest drives deck.gl: rendering, data loading, live updates, picking, widgets, and validation. No build step.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
9
9
|
"author": "NikaGeospatial",
|
|
10
|
-
"homepage": "https://
|
|
10
|
+
"homepage": "https://www.nikaplanet.com/onlymap",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
13
|
"url": "git+https://github.com/NikaGeospatial/onlymapjs.git"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: onlymapjs
|
|
3
|
-
description: Build, edit, debug, or review OnlyMapJS declarative HTML maps and dashboards. Use when a user asks for an interactive map, deck.gl-style visualization, geospatial dashboard, live fleet/telemetry map, choropleth, popup/tooltip map, map story/tour, manual drawing/sketch map, 3D map assets, or help with OnlyMapJS syntax, validation, widgets, data formats, testing, or publishing examples.
|
|
3
|
+
description: Build, edit, debug, or review OnlyMapJS declarative HTML maps and dashboards, or React maps via the @nika-js/onlymap/react adapter. Use when a user asks for an interactive map, deck.gl-style visualization, geospatial dashboard, live fleet/telemetry map, choropleth, popup/tooltip map, map story/tour, manual drawing/sketch map, 3D map assets, a React map component, a map page shared as a single HTML file (incl. no-JS fallbacks for chat/email previews), or help with OnlyMapJS syntax, validation, widgets, data formats, testing, or publishing examples.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OnlyMapJS
|
|
@@ -23,7 +23,17 @@ Use OnlyMapJS as a declarative HTML map library. Write custom elements such as `
|
|
|
23
23
|
</script>
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
For no-build CDN examples, use a published module URL such as `https://esm.sh/@nika-js/onlymap@0.
|
|
26
|
+
For no-build CDN examples, use a published module URL such as `https://esm.sh/@nika-js/onlymap@0.2.0`.
|
|
27
|
+
|
|
28
|
+
## React Projects
|
|
29
|
+
|
|
30
|
+
In a React codebase, do NOT render `om-*` elements from JSX — React and the library would contend over the same DOM. Use the first-party adapter instead:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { OmMap, OmLayer, OmWidget, OmOverlay, useOmMap } from "@nika-js/onlymap/react";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The adapter inverts several HTML-manifest rules: props are camelCase deck.gl props, accessors are plain JS functions (`getFillColor={d => ...}` — no `$field` expression language, no `js` opt-in), and interactions are `onClick`/`onHover` handlers plus React state, not `<om-behavior>` or state-mutating actions. Load `references/react.md` before writing React map code.
|
|
27
37
|
|
|
28
38
|
## Required References
|
|
29
39
|
|
|
@@ -31,6 +41,7 @@ Load the smallest reference needed for the task:
|
|
|
31
41
|
|
|
32
42
|
- `references/syntax.md` — element vocabulary, attributes, data formats, accessors, actions, widgets, overlays, drawing, 3D, built-in layer types.
|
|
33
43
|
- `references/patterns.md` — copyable manifest patterns for common map requests.
|
|
44
|
+
- `references/react.md` — the React adapter: components, the useOmMap hook, HTML-vs-React rule differences, testing.
|
|
34
45
|
- `references/testing.md` — validation, snapshot, headless harness, and browser testing workflow.
|
|
35
46
|
|
|
36
47
|
## Non-Negotiable Syntax Rules
|
|
@@ -50,12 +61,16 @@ Load the smallest reference needed for the task:
|
|
|
50
61
|
- Sparse rich HTML at one geographic location -> `<om-overlay>`.
|
|
51
62
|
- Many labels/badges -> `<om-layer type="PopupLayer">`.
|
|
52
63
|
- Guided tour or narrative sequence -> `<om-story>` with `<om-step>` siblings that reference existing layers/overlays by id.
|
|
64
|
+
- Basemap choice or user-switchable basemaps -> `basemap` presets (`positron`, `liberty`, `dark-matter`, `osm`, ...) + `<om-widget type="basemap-switcher">`; MapTiler custom styles via a style URL or `basemap-key`.
|
|
53
65
|
- Live entity updates -> `wss://` stream with `key` and optional `source` decoder.
|
|
54
66
|
- REST snapshot that changes over time -> `refresh="5s"`.
|
|
55
67
|
- User sketching -> `data="draw:sketch"` layer plus `<om-widget type="draw" target="sketch">`.
|
|
68
|
+
- Page may travel as a file (shared, emailed, downloaded) or be embedded -> add an `<om-fallback>` child to `<om-map>`. Chat-app and email previews render HTML with JavaScript disabled (iOS QuickLook), so the map cannot boot there; the fallback is what recipients see instead. It is hidden automatically once the map boots. Good practice on every complete page — without one, the stylesheet shows a generic text-only banner.
|
|
56
69
|
|
|
57
70
|
## Output Expectations
|
|
58
71
|
|
|
59
72
|
When creating a map page, output a complete runnable HTML file unless the user asks for a fragment. Include CSS only as needed for page sizing or custom widgets/overlays. Keep the first screen the usable map, not a landing page.
|
|
60
73
|
|
|
74
|
+
Include an `<om-fallback>` element (a short "this map requires JavaScript — open in a browser" message, optionally with a hosted-version link) as a direct child of `<om-map>` on any complete page. For the fallback to render in no-JS previews, `onlymapjs.css` must load without JavaScript — a real `<link rel="stylesheet">` or inlined `<style>`, not only a runtime `import` (bundler-emitted stylesheets are fine).
|
|
75
|
+
|
|
61
76
|
When modifying an existing page, preserve the user's data URLs, layer ids, and styling unless the request requires changing them.
|
|
@@ -29,11 +29,17 @@ Use these patterns as starting points. Replace data URLs, layer ids, fields, cen
|
|
|
29
29
|
pickable></om-layer>
|
|
30
30
|
<om-widget type="legend" position="bottom-right" title="Layers"></om-widget>
|
|
31
31
|
<om-widget type="zoom-controls" position="top-right"></om-widget>
|
|
32
|
+
<!-- Shown only where scripts never run (chat-app/email file previews) -->
|
|
33
|
+
<om-fallback>
|
|
34
|
+
<p>This interactive map requires JavaScript — open this file in a web browser.</p>
|
|
35
|
+
</om-fallback>
|
|
32
36
|
</om-map>
|
|
33
37
|
</body>
|
|
34
38
|
</html>
|
|
35
39
|
```
|
|
36
40
|
|
|
41
|
+
Every complete-page pattern below should also carry an `<om-fallback>` (omitted for brevity) — see the good-practice rule in SKILL.md.
|
|
42
|
+
|
|
37
43
|
## Click Popup
|
|
38
44
|
|
|
39
45
|
```html
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# React adapter — `@nika-js/onlymap/react`
|
|
2
|
+
|
|
3
|
+
Real components over the same engine as the HTML manifest. React never renders `om-*` elements — components feed a typed programmatic front-end, so there is no DOM contention with the library's reconciler. React ≥ 18 (`npm install @nika-js/onlymap react react-dom`).
|
|
4
|
+
|
|
5
|
+
## Rules that INVERT the HTML-manifest rules
|
|
6
|
+
|
|
7
|
+
- Props are **camelCase deck.gl props** (`getFillColor`, `radiusMinPixels`), not kebab-case attributes.
|
|
8
|
+
- Accessors are **plain JS functions**: `getFillColor={d => d.mag > 6 ? [214,40,40] : [252,191,73]}`. Never use `$field` expressions or `scale()` strings here; never add a `js` attribute (there is none).
|
|
9
|
+
- Interactions are **event handlers + state**, not `<om-behavior>`. Toggle a layer by rendering `visible={false}`; filter by changing `filterRange`. The state-mutating actions (`toggle-layer`, `show-overlay`, `fade`, story/draw actions) are not dispatched on this path — a console warning points back to props. Camera actions (`fly-to`, `zoom-to-feature`, `zoom-in`/`-out`), `pulse`, `populate`, and custom `OmMap.registerAction` handlers work via `emit`.
|
|
10
|
+
- Keep inline `data` references **stable across renders** (`useMemo`/`useState`) — data reactivity diffs by reference. deck.gl ignores accessor function identity; pass `updateTriggers={{ getFillColor: theme }}` when an accessor's *output* changes.
|
|
11
|
+
- Stories and the draw widget are HTML-manifest-only for now.
|
|
12
|
+
|
|
13
|
+
## Complete example
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { useState } from "react";
|
|
17
|
+
import { OmMap, OmLayer, OmWidget, OmOverlay, useOmMap } from "@nika-js/onlymap/react";
|
|
18
|
+
|
|
19
|
+
function QuakeMap() {
|
|
20
|
+
const [visible, setVisible] = useState(true);
|
|
21
|
+
return (
|
|
22
|
+
<OmMap center={[-119, 36]} zoom={5} basemap="maplibre" style={{ height: "100vh" }}>
|
|
23
|
+
<OmLayer id="quakes" type="ScatterplotLayer" data="/quakes.csv" label="Earthquakes"
|
|
24
|
+
visible={visible} pickable
|
|
25
|
+
getPosition={(d) => [d.longitude, d.latitude]}
|
|
26
|
+
getFillColor={(d) => (d.mag >= 6 ? [214, 40, 40] : [252, 191, 73])}
|
|
27
|
+
radiusMinPixels={3}
|
|
28
|
+
onClick={(sel) => console.log(sel.object)} />
|
|
29
|
+
<OmWidget position="top-left"><StatsPanel onToggle={() => setVisible(!visible)} /></OmWidget>
|
|
30
|
+
<OmOverlay anchorFrom="selection" layer="quakes">
|
|
31
|
+
{(sel) => sel && <div className="card">M{sel.object.mag} — {sel.object.place}</div>}
|
|
32
|
+
</OmOverlay>
|
|
33
|
+
</OmMap>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function StatsPanel({ onToggle }) {
|
|
38
|
+
const ctx = useOmMap(["viewport", "data:quakes"]); // watch tokens re-render the component
|
|
39
|
+
return (
|
|
40
|
+
<div className="panel">
|
|
41
|
+
{ctx.stats("quakes", "mag").count} quakes at z{ctx.viewport.zoom.toFixed(1)}
|
|
42
|
+
<button onClick={onToggle}>Toggle</button>
|
|
43
|
+
<button onClick={() => ctx.emit("fly-to", { center: [140, 38], zoom: 4, duration: 1200 })}>Japan</button>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Component surface
|
|
50
|
+
|
|
51
|
+
- **`<OmMap>`** — `center`/`zoom`/`pitch`/`bearing` (initial; later changes move the camera, unchanged props never fight user panning), `basemap`, `headless`, `onReady`, `onViewStateChange`, `onRuntimeError`. Give it a size via `style`/`className`. `ref` exposes the imperative `MapController` handle: `flyTo`, `setView`, `emit`, `getLayers`, `getSelection`, `injectPick`, `ready` (promise), `project`.
|
|
52
|
+
- **`<OmLayer>`** — `id` + `type` (any registered deck.gl layer type) + deck props. `data`: stable inline reference or URL string (full Data Layer: CSV/Arrow/Shapefile/KML formats, `ws(s)://` streams via `source`/`streamKey`/`flush`, `refresh` polling). `label`/`color` feed `ctx.layers`; `filterField`/`filterRange` = GPU filter; `onClick`/`onHover` receive the flattened picked object (`onHover(null)` = pointer left).
|
|
53
|
+
- **`<OmWidget>`** — positioning shell: `position="top-left|top-right|bottom-left|bottom-right"` + arbitrary JSX. Widgets sharing a corner stack.
|
|
54
|
+
- **`<OmOverlay>`** — geo-anchored HTML with managed projection/tracking/culling. `anchor={[lng, lat]}` or `anchorFrom="selection"` (+ `layer` to scope which picks move it); children may be `(selection) => JSX`; `anchorOffset` (default `bottom-center`); `interactive={false}` for hover-following tooltips.
|
|
55
|
+
- **`useOmMap(watch?)`** — the same `ctx` contract HTML widget scripts get, typed: `layers`, `viewport`, `selection`, `emit`, `data()`, `dataInViewport()`, `stats()`. Watch tokens: `"viewport"`, `"selection"`, `"layers"`, `"data:<layerId>"`.
|
|
56
|
+
|
|
57
|
+
## Testing (no browser, no GPU)
|
|
58
|
+
|
|
59
|
+
`<OmMap headless>` runs real projection math under jsdom/happy-dom:
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
const ref = createRef<OmMapHandle>();
|
|
63
|
+
render(<OmMap ref={ref} headless><OmLayer id="pts" type="ScatterplotLayer" data={rows} getPosition={p} /></OmMap>);
|
|
64
|
+
await ref.current!.ready;
|
|
65
|
+
ref.current!.injectPick({ layerId: "pts", object: rows[0], index: 0, coordinate: [0, 0], pixel: [0, 0], type: "click" });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`injectPick` rides the same selection path as real GPU picks — `onClick`, `useOmMap(["selection"])`, and selection-anchored overlays all react. For browser e2e, expose the `ref` handle (e.g. on `window`) as the readiness/projection probe — a React page has no `<om-map>` element to await.
|
|
@@ -19,13 +19,13 @@ Static CDN page:
|
|
|
19
19
|
<script type="module" src="https://esm.sh/@nika-js/onlymap@0.1.0"></script>
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
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).
|
|
23
23
|
|
|
24
24
|
## Elements
|
|
25
25
|
|
|
26
26
|
### `<om-map>`
|
|
27
27
|
|
|
28
|
-
Root element. Children are layers, widgets, overlays, behaviors, and
|
|
28
|
+
Root element. Children are layers, widgets, overlays, behaviors, stories, and an optional fallback.
|
|
29
29
|
|
|
30
30
|
Common attributes:
|
|
31
31
|
|
|
@@ -33,7 +33,8 @@ Common attributes:
|
|
|
33
33
|
- `zoom="11"`
|
|
34
34
|
- `pitch="55"`
|
|
35
35
|
- `bearing="20"`
|
|
36
|
-
- `basemap
|
|
36
|
+
- `basemap` — a free preset (`liberty`, `bright`, `positron`, `dark-matter`, `voyager`, `osm`; keyed `maptiler-streets|dataviz|satellite` with `basemap-key="…"` or `OmMap.configureBasemap({ maptilerKey })`), `maplibre` (bare demo style), a MapLibre style URL, or `none` (standalone canvas). The attribute is live: writing it switches the basemap in place (camera and layers survive). Register more with `OmMap.registerBasemap(name, { style })`.
|
|
37
|
+
- `attribution="false"` to opt out of the automatic provider-attribution control (only if you render equivalent credits yourself)
|
|
37
38
|
- `validate` to show live validation errors during authoring
|
|
38
39
|
- `headless width="800" height="600"` for test harness use
|
|
39
40
|
|
|
@@ -178,6 +179,7 @@ Built-ins:
|
|
|
178
179
|
- `draw`
|
|
179
180
|
- `vega-lite`
|
|
180
181
|
- `player`
|
|
182
|
+
- `basemap-switcher` — radio list of presets; `options="positron dark-matter osm"` (default: every keyless registered preset)
|
|
181
183
|
|
|
182
184
|
Positions: `top-left`, `top-right`, `bottom-left`, `bottom-right`.
|
|
183
185
|
|
|
@@ -187,6 +189,7 @@ Examples:
|
|
|
187
189
|
<om-widget type="legend" position="bottom-right" title="Layers" interactive></om-widget>
|
|
188
190
|
<om-widget type="filter" layer="quakes" field="magnitude" position="top-left"></om-widget>
|
|
189
191
|
<om-widget type="draw" target="sketch" modes="point line polygon" save="both"></om-widget>
|
|
192
|
+
<om-widget type="basemap-switcher" options="positron dark-matter liberty osm" position="top-right"></om-widget>
|
|
190
193
|
```
|
|
191
194
|
|
|
192
195
|
Custom widget:
|
|
@@ -240,6 +243,26 @@ Example:
|
|
|
240
243
|
<om-behavior on="click" layer="quakes" action="show-overlay" target="detail"></om-behavior>
|
|
241
244
|
```
|
|
242
245
|
|
|
246
|
+
### `<om-fallback>`
|
|
247
|
+
|
|
248
|
+
Static content shown only where scripts never run — chat-app/email file previews (iOS QuickLook), file managers, sandboxed webviews. Hidden automatically once the map boots. Good practice on every complete page, especially one that may be shared as a file.
|
|
249
|
+
|
|
250
|
+
Rules:
|
|
251
|
+
|
|
252
|
+
- Direct child of `<om-map>` (validation warns elsewhere), one per map.
|
|
253
|
+
- No attributes; plain HTML content — links work, so include a hosted-version URL when one exists.
|
|
254
|
+
- Without an `<om-fallback>`, the stylesheet shows a generic text-only banner instead.
|
|
255
|
+
- Requires `onlymapjs.css` to load without JavaScript (see Import Patterns above).
|
|
256
|
+
|
|
257
|
+
Example:
|
|
258
|
+
|
|
259
|
+
```html
|
|
260
|
+
<om-fallback>
|
|
261
|
+
<p><strong>This interactive map requires JavaScript.</strong><br />
|
|
262
|
+
Open this file in a web browser, or visit <a href="https://example.com/map">the hosted version</a>.</p>
|
|
263
|
+
</om-fallback>
|
|
264
|
+
```
|
|
265
|
+
|
|
243
266
|
### `<om-behavior>`
|
|
244
267
|
|
|
245
268
|
Declarative event to action binding.
|
|
@@ -254,6 +277,7 @@ Common built-in actions:
|
|
|
254
277
|
- `highlight-feature`
|
|
255
278
|
- `zoom-to-feature`
|
|
256
279
|
- `filter-layer`
|
|
280
|
+
- `set-basemap` — payload `{ basemap }`; writes the `<om-map basemap>` attribute
|
|
257
281
|
- `zoom-in`, `zoom-out`
|
|
258
282
|
- `fly-to`
|
|
259
283
|
- story actions: `story-play`, `story-pause`, `story-seek`
|