@nika-js/onlymap 0.2.3 → 0.3.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 +13 -0
- package/LICENSE.md +4 -0
- package/README.md +30 -7
- package/THIRD-PARTY-LICENSES.md +7874 -0
- package/dist/{Arrow.dom-7AXne1TU.js → Arrow.dom-BNjbQ9jb.js} +23 -23
- package/dist/LercDecode.es-CVmNpXBp.js +303 -0
- package/dist/assets/LercDecode.es-BJb2dZu5.js +305 -0
- package/dist/assets/__vite-browser-external-DDArsqdc.js +29 -0
- package/dist/assets/lerc-wasm.wasm +0 -0
- package/dist/assets/lzw-BY5a_5nb.js +83 -0
- package/dist/assets/worker-DtIrTJB7.js +305 -0
- package/dist/assets/zstd-QGAv3PMm.js +383 -0
- package/dist/{basemap-BdvB-SHy.js → basemap-BSb-g03Z.js} +5729 -5684
- package/dist/basemap-registry.d.ts +10 -0
- package/dist/basemap.d.ts +23 -0
- package/dist/color.d.ts +9 -0
- package/dist/{convert-arrow-schema-CvZ3cT5m.js → convert-arrow-schema-DrAihRf9.js} +31 -31
- package/dist/ctx.d.ts +3 -0
- package/dist/deck.d.ts +28 -0
- package/dist/deck.js +16 -0
- package/dist/elements/om-map.d.ts +29 -0
- package/dist/html-data.d.ts +2 -2
- package/dist/index-CIEkseeV.js +3108 -0
- package/dist/index-D67FynN5.js +594 -0
- package/dist/{index-CJOMgp8k.js → index-QSkZjzIL.js} +4 -4
- package/dist/index-WeMwLoaQ.js +1446 -0
- package/dist/{index-BxzDKZpu.js → index-lV5eG2Xt.js} +22439 -21347
- package/dist/index.d.ts +13 -0
- package/dist/ir-snapshot.d.ts +2 -0
- package/dist/ir.d.ts +10 -0
- package/dist/layer-registry.d.ts +15 -1
- package/dist/legend-spec.d.ts +66 -0
- package/dist/lerc-DJzRIT6z.js +30 -0
- package/dist/lerc-wasm.wasm +0 -0
- package/dist/lzw-BY5a_5nb.js +83 -0
- package/dist/mgrs-BY9bIvp4.js +799 -0
- package/dist/onlymapjs.css +1 -1
- package/dist/onlymapjs.js +55 -35
- package/dist/programmatic.d.ts +35 -0
- package/dist/raster-BKf1dx54.js +8843 -0
- package/dist/raster.d.ts +61 -0
- package/dist/react/om-layer.d.ts +2 -0
- package/dist/react.js +18 -16
- package/dist/{recordbatch-HRu0SMKp.js → recordbatch-Bpc0uxFn.js} +200 -200
- package/dist/runtime-core.d.ts +73 -1
- package/dist/scene-lighting.d.ts +83 -0
- package/dist/selection.d.ts +1 -1
- package/dist/snapshot.d.ts +14 -0
- package/dist/{table-accessors-DBjWgN0C.js → table-accessors-CYWTzpQI.js} +71 -76
- package/dist/terrain.d.ts +113 -0
- package/dist/version.d.ts +1 -1
- package/dist/zstd-jXobGRcq.js +14 -0
- package/docs/custom-layers.md +99 -0
- package/llms.txt +5 -5
- package/onlymapjs.html-data.json +163 -29
- package/package.json +35 -15
- package/skills/onlymapjs/SKILL.md +3 -1
- package/skills/onlymapjs/references/syntax.md +53 -3
- package/dist/index-BVQ0s1Zh.js +0 -1457
- package/dist/index-CvBHiOGD.js +0 -605
- package/dist/index-Vc8QfNEf.js +0 -3907
- package/dist/onlymapjs.umd.cjs +0 -8634
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scene lighting (spec: "Scene Lighting") — the manifest surface over
|
|
3
|
+
* deck.gl's LightingEffect, resolving the backlog TODO ("Lighting/effects
|
|
4
|
+
* manifest surface"). Attributes on <om-map>, the basemap= precedent:
|
|
5
|
+
* singleton scene state as attributes gets undo/redo for free (attribute
|
|
6
|
+
* history) and live switching through the same MutationObserver path.
|
|
7
|
+
*
|
|
8
|
+
* <om-map lighting="daylight">
|
|
9
|
+
* <om-map lighting="custom" lighting-ambient="0.6" lighting-sun="1.5"
|
|
10
|
+
* lighting-sun-azimuth="135" lighting-sun-elevation="45">
|
|
11
|
+
* <om-map lighting="daylight" lighting-sun-date="2026-07-15T14:00:00Z">
|
|
12
|
+
*
|
|
13
|
+
* The sun is ALWAYS a DirectionalLight driven by azimuth/elevation;
|
|
14
|
+
* `lighting-sun-date` is sugar that computes az/el from solar position at
|
|
15
|
+
* the map center when lighting is applied (deliberately NOT deck's
|
|
16
|
+
* experimental `_SunLight`, which recomputes per frame from the viewport —
|
|
17
|
+
* an attribute-declared scene should be deterministic, and the underscore
|
|
18
|
+
* API is upgrade churn). Absent `lighting` = deck's default lights —
|
|
19
|
+
* today's behavior, so the whole surface is additive.
|
|
20
|
+
*/
|
|
21
|
+
import { AmbientLight, _CameraLight as CameraLight, DirectionalLight, LightingEffect } from "@deck.gl/core";
|
|
22
|
+
export interface LightingIR {
|
|
23
|
+
/** Preset the values were seeded from (validation/UI echo; "custom" for a fully hand-tuned scene). */
|
|
24
|
+
preset: LightingPresetName;
|
|
25
|
+
/** Ambient intensity — always-on fill. */
|
|
26
|
+
ambient: number;
|
|
27
|
+
/** Sun (directional) intensity; 0 omits the sun light entirely. */
|
|
28
|
+
sun: number;
|
|
29
|
+
/** Sun compass bearing, ° clockwise from north. */
|
|
30
|
+
sunAzimuth: number;
|
|
31
|
+
/** Sun height above the horizon, ° (0 = horizon, 90 = zenith). */
|
|
32
|
+
sunElevation: number;
|
|
33
|
+
/** Camera-following fill intensity (model inspection); 0 omits it. */
|
|
34
|
+
camera: number;
|
|
35
|
+
/** Epoch ms — when set, az/el are recomputed from solar position at apply time. */
|
|
36
|
+
sunDate?: number;
|
|
37
|
+
}
|
|
38
|
+
export type LightingPresetName = "daylight" | "studio" | "flat" | "custom";
|
|
39
|
+
export declare const LIGHTING_PRESET_NAMES: readonly ["daylight", "studio", "flat", "custom"];
|
|
40
|
+
export declare function isLightingPreset(name: string): name is LightingPresetName;
|
|
41
|
+
/** Programmatic twin of the lighting-* attributes (MapControllerOptions.lighting / setLighting). */
|
|
42
|
+
export interface LightingOptions {
|
|
43
|
+
preset?: LightingPresetName;
|
|
44
|
+
ambient?: number;
|
|
45
|
+
sun?: number;
|
|
46
|
+
sunAzimuth?: number;
|
|
47
|
+
sunElevation?: number;
|
|
48
|
+
camera?: number;
|
|
49
|
+
/** Epoch ms or ISO 8601 — the lighting-sun-date twin. */
|
|
50
|
+
sunDate?: number | string;
|
|
51
|
+
}
|
|
52
|
+
/** Preset seeds values; explicit fields override individual seeds; sunDate (resolved at apply time) wins over az/el. */
|
|
53
|
+
export declare function resolveLighting(options: LightingOptions): LightingIR;
|
|
54
|
+
/**
|
|
55
|
+
* `lighting*` attributes → IR. Returns null when `lighting` itself is
|
|
56
|
+
* absent (deck default lights; stray lighting-* overrides without it are
|
|
57
|
+
* inert — validation warns). Malformed numbers fall back to the preset seed
|
|
58
|
+
* (validation flags them; the live path must still render something).
|
|
59
|
+
*/
|
|
60
|
+
export declare function parseLightingAttrs(getAttr: (name: string) => string | null): LightingIR | null;
|
|
61
|
+
/**
|
|
62
|
+
* Solar azimuth/elevation at a timestamp + location, in the manual-sun
|
|
63
|
+
* convention (azimuth ° CW from north, elevation ° above horizon). The
|
|
64
|
+
* standard suncalc derivation (the same math deck's `_SunLight` uses via
|
|
65
|
+
* @math.gl/sun): solar azimuth measured south→west, so matching the
|
|
66
|
+
* DirectionalLight convention is `azimuth = solar + 180°`. Below-horizon
|
|
67
|
+
* sun clamps to the horizon — a flat scene can't render a sun beneath it.
|
|
68
|
+
*/
|
|
69
|
+
export declare function solarAzElDegrees(timestamp: number, latitude: number, longitude: number): {
|
|
70
|
+
azimuth: number;
|
|
71
|
+
elevation: number;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* IR → the named lights map a LightingEffect is constructed from —
|
|
75
|
+
* separated so tests can assert composition without reaching into
|
|
76
|
+
* LightingEffect's private fields. The ambient light is always present;
|
|
77
|
+
* sun and camera lights only at intensity > 0 (deck renders a 0-intensity
|
|
78
|
+
* light as subtle noise, not nothing). `center` (current map center) feeds
|
|
79
|
+
* the sunDate → az/el resolution.
|
|
80
|
+
*/
|
|
81
|
+
export declare function buildLights(ir: LightingIR, center?: [longitude: number, latitude: number]): Record<string, AmbientLight | DirectionalLight | CameraLight>;
|
|
82
|
+
/** IR → deck.gl LightingEffect (see buildLights for the composition rules). */
|
|
83
|
+
export declare function buildLightingEffect(ir: LightingIR, center?: [longitude: number, latitude: number]): LightingEffect;
|
package/dist/selection.d.ts
CHANGED
|
@@ -27,5 +27,5 @@ interface PickingInfoLike {
|
|
|
27
27
|
x: number;
|
|
28
28
|
y: number;
|
|
29
29
|
}
|
|
30
|
-
export declare function toSelection(info: PickingInfoLike, type: "hover" | "click"): Selection | null;
|
|
30
|
+
export declare function toSelection(info: PickingInfoLike, type: "hover" | "click", resolveLayerId?: (renderedId: string) => string): Selection | null;
|
|
31
31
|
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot serialization (spec: "Snapshot API") — shared by OmMapElement
|
|
3
|
+
* and MapController: the composite canvas RuntimeCore.snapshot() produces,
|
|
4
|
+
* serialized to the consumer's preferred shape.
|
|
5
|
+
*/
|
|
6
|
+
export interface SnapshotOptions {
|
|
7
|
+
/** Image MIME type — default "image/png". */
|
|
8
|
+
type?: "image/png" | "image/jpeg" | "image/webp";
|
|
9
|
+
/** Lossy-format quality 0–1 (jpeg/webp). */
|
|
10
|
+
quality?: number;
|
|
11
|
+
/** Output shape — default "dataURL" (what print/export pipelines embed directly); "blob" for uploads/files. */
|
|
12
|
+
as?: "dataURL" | "blob";
|
|
13
|
+
}
|
|
14
|
+
export declare function serializeSnapshot(canvas: HTMLCanvasElement, opts: SnapshotOptions): Promise<string | Blob>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
switch (typeof e == "object" && (e == null ? void 0 : e.shape)) {
|
|
1
|
+
function d(e) {
|
|
2
|
+
switch (typeof e == "object" && e?.shape) {
|
|
4
3
|
case "array-row-table":
|
|
5
4
|
case "object-row-table":
|
|
6
5
|
return Array.isArray(e.data);
|
|
@@ -9,12 +8,12 @@ function w(e) {
|
|
|
9
8
|
case "columnar-table":
|
|
10
9
|
return e.data && typeof e.data == "object";
|
|
11
10
|
case "arrow-table":
|
|
12
|
-
return
|
|
11
|
+
return e?.data?.numRows !== void 0;
|
|
13
12
|
default:
|
|
14
13
|
return !1;
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
|
-
function
|
|
16
|
+
function i(e) {
|
|
18
17
|
switch (e.shape) {
|
|
19
18
|
case "array-row-table":
|
|
20
19
|
case "object-row-table":
|
|
@@ -24,8 +23,8 @@ function l(e) {
|
|
|
24
23
|
case "arrow-table":
|
|
25
24
|
return e.data.numRows;
|
|
26
25
|
case "columnar-table":
|
|
27
|
-
for (const
|
|
28
|
-
return
|
|
26
|
+
for (const t of Object.values(e.data))
|
|
27
|
+
return t.length || 0;
|
|
29
28
|
return 0;
|
|
30
29
|
default:
|
|
31
30
|
throw new Error("table");
|
|
@@ -34,7 +33,7 @@ function l(e) {
|
|
|
34
33
|
function g(e) {
|
|
35
34
|
if (e.schema)
|
|
36
35
|
return e.schema.fields.length;
|
|
37
|
-
if (
|
|
36
|
+
if (i(e) === 0)
|
|
38
37
|
throw new Error("empty table");
|
|
39
38
|
switch (e.shape) {
|
|
40
39
|
case "array-row-table":
|
|
@@ -51,154 +50,150 @@ function g(e) {
|
|
|
51
50
|
throw new Error("table");
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
|
-
function j(e, r,
|
|
55
|
-
var o;
|
|
53
|
+
function j(e, r, t) {
|
|
56
54
|
switch (e.shape) {
|
|
57
55
|
case "array-row-table":
|
|
58
|
-
const
|
|
59
|
-
return e.data[r][
|
|
56
|
+
const o = m(e, t);
|
|
57
|
+
return e.data[r][o];
|
|
60
58
|
case "object-row-table":
|
|
61
|
-
return e.data[r][
|
|
59
|
+
return e.data[r][t];
|
|
62
60
|
case "geojson-table":
|
|
63
|
-
return e.features[r][
|
|
61
|
+
return e.features[r][t];
|
|
64
62
|
case "columnar-table":
|
|
65
|
-
return e.data[
|
|
63
|
+
return e.data[t][r];
|
|
66
64
|
case "arrow-table":
|
|
67
|
-
const
|
|
68
|
-
return
|
|
65
|
+
const n = e.data, f = n.schema.fields.findIndex((c) => c.name === t);
|
|
66
|
+
return n.getChildAt(f)?.get(r);
|
|
69
67
|
default:
|
|
70
68
|
throw new Error("todo");
|
|
71
69
|
}
|
|
72
70
|
}
|
|
73
|
-
function y(e, r,
|
|
74
|
-
var o;
|
|
71
|
+
function y(e, r, t) {
|
|
75
72
|
switch (e.shape) {
|
|
76
73
|
case "array-row-table":
|
|
77
|
-
return e.data[r][
|
|
74
|
+
return e.data[r][t];
|
|
78
75
|
case "object-row-table":
|
|
79
|
-
const
|
|
80
|
-
return e.data[r][
|
|
76
|
+
const o = l(e, t);
|
|
77
|
+
return e.data[r][o];
|
|
81
78
|
case "geojson-table":
|
|
82
|
-
const
|
|
83
|
-
return e.features[r][
|
|
79
|
+
const u = l(e, t);
|
|
80
|
+
return e.features[r][u];
|
|
84
81
|
case "columnar-table":
|
|
85
|
-
const
|
|
86
|
-
return e.data[
|
|
82
|
+
const n = l(e, t);
|
|
83
|
+
return e.data[n][r];
|
|
87
84
|
case "arrow-table":
|
|
88
|
-
return
|
|
85
|
+
return e.data.getChildAt(t)?.get(r);
|
|
89
86
|
default:
|
|
90
87
|
throw new Error("todo");
|
|
91
88
|
}
|
|
92
89
|
}
|
|
93
90
|
function m(e, r) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (a === void 0)
|
|
91
|
+
const t = e.schema?.fields.findIndex((o) => o.name === r);
|
|
92
|
+
if (t === void 0)
|
|
97
93
|
throw new Error(r);
|
|
98
|
-
return
|
|
94
|
+
return t;
|
|
99
95
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (!a)
|
|
96
|
+
function l(e, r) {
|
|
97
|
+
const t = e.schema?.fields[r]?.name;
|
|
98
|
+
if (!t)
|
|
104
99
|
throw new Error(`${r}`);
|
|
105
|
-
return
|
|
100
|
+
return t;
|
|
106
101
|
}
|
|
107
|
-
function T(e, r,
|
|
102
|
+
function T(e, r, t, o) {
|
|
108
103
|
switch (e.shape) {
|
|
109
104
|
case "object-row-table":
|
|
110
105
|
return o ? Object.fromEntries(Object.entries(e.data[r])) : e.data[r];
|
|
111
106
|
case "array-row-table":
|
|
112
107
|
if (e.schema) {
|
|
113
|
-
const s =
|
|
114
|
-
for (let
|
|
115
|
-
s[e.schema.fields[
|
|
108
|
+
const s = t || {};
|
|
109
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
110
|
+
s[e.schema.fields[a].name] = e.data[r][a];
|
|
116
111
|
return s;
|
|
117
112
|
}
|
|
118
113
|
throw new Error("no schema");
|
|
119
114
|
case "geojson-table":
|
|
120
115
|
if (e.schema) {
|
|
121
|
-
const s =
|
|
122
|
-
for (let
|
|
123
|
-
s[e.schema.fields[
|
|
116
|
+
const s = t || {};
|
|
117
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
118
|
+
s[e.schema.fields[a].name] = e.features[r][a];
|
|
124
119
|
return s;
|
|
125
120
|
}
|
|
126
121
|
throw new Error("no schema");
|
|
127
122
|
case "columnar-table":
|
|
128
123
|
if (e.schema) {
|
|
129
|
-
const s =
|
|
130
|
-
for (let
|
|
131
|
-
s[e.schema.fields[
|
|
124
|
+
const s = t || {};
|
|
125
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
126
|
+
s[e.schema.fields[a].name] = e.data[e.schema.fields[a].name][r];
|
|
132
127
|
return s;
|
|
133
128
|
} else {
|
|
134
|
-
const s =
|
|
135
|
-
for (const [
|
|
136
|
-
s[
|
|
129
|
+
const s = t || {};
|
|
130
|
+
for (const [a, h] of Object.entries(e.data))
|
|
131
|
+
s[a] = h[r];
|
|
137
132
|
return s;
|
|
138
133
|
}
|
|
139
134
|
case "arrow-table":
|
|
140
|
-
const
|
|
141
|
-
for (let s = 0; s <
|
|
142
|
-
|
|
143
|
-
return
|
|
135
|
+
const u = e.data, n = t || {}, f = u.get(r), c = u.schema;
|
|
136
|
+
for (let s = 0; s < c.fields.length; s++)
|
|
137
|
+
n[c.fields[s].name] = f?.[c.fields[s].name];
|
|
138
|
+
return n;
|
|
144
139
|
default:
|
|
145
140
|
throw new Error("shape");
|
|
146
141
|
}
|
|
147
142
|
}
|
|
148
|
-
function
|
|
143
|
+
function w(e, r, t, o) {
|
|
149
144
|
switch (e.shape) {
|
|
150
145
|
case "array-row-table":
|
|
151
146
|
return o ? Array.from(e.data[r]) : e.data[r];
|
|
152
147
|
case "object-row-table":
|
|
153
148
|
if (e.schema) {
|
|
154
|
-
const s =
|
|
155
|
-
for (let
|
|
156
|
-
s[
|
|
149
|
+
const s = t || [];
|
|
150
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
151
|
+
s[a] = e.data[r][e.schema.fields[a].name];
|
|
157
152
|
return s;
|
|
158
153
|
}
|
|
159
154
|
return Object.values(e.data[r]);
|
|
160
155
|
case "geojson-table":
|
|
161
156
|
if (e.schema) {
|
|
162
|
-
const s =
|
|
163
|
-
for (let
|
|
164
|
-
s[
|
|
157
|
+
const s = t || [];
|
|
158
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
159
|
+
s[a] = e.features[r][e.schema.fields[a].name];
|
|
165
160
|
return s;
|
|
166
161
|
}
|
|
167
162
|
return Object.values(e.features[r]);
|
|
168
163
|
case "columnar-table":
|
|
169
164
|
if (e.schema) {
|
|
170
|
-
const s =
|
|
171
|
-
for (let
|
|
172
|
-
s[
|
|
165
|
+
const s = t || [];
|
|
166
|
+
for (let a = 0; a < e.schema.fields.length; a++)
|
|
167
|
+
s[a] = e.data[e.schema.fields[a].name][r];
|
|
173
168
|
return s;
|
|
174
169
|
} else {
|
|
175
|
-
const s =
|
|
176
|
-
let
|
|
170
|
+
const s = t || [];
|
|
171
|
+
let a = 0;
|
|
177
172
|
for (const h of Object.values(e.data))
|
|
178
|
-
s[
|
|
173
|
+
s[a] = h[r], a++;
|
|
179
174
|
return s;
|
|
180
175
|
}
|
|
181
176
|
case "arrow-table":
|
|
182
|
-
const
|
|
183
|
-
for (let s = 0; s <
|
|
184
|
-
|
|
185
|
-
return
|
|
177
|
+
const u = e.data, n = t || [], f = u.get(r), c = u.schema;
|
|
178
|
+
for (let s = 0; s < c.fields.length; s++)
|
|
179
|
+
n[s] = f?.[c.fields[s].name];
|
|
180
|
+
return n;
|
|
186
181
|
default:
|
|
187
182
|
throw new Error("shape");
|
|
188
183
|
}
|
|
189
184
|
}
|
|
190
185
|
function* p(e, r = []) {
|
|
191
|
-
const
|
|
192
|
-
for (let o = 0; o <
|
|
193
|
-
yield
|
|
186
|
+
const t = i(e);
|
|
187
|
+
for (let o = 0; o < t; o++)
|
|
188
|
+
yield w(e, o, r);
|
|
194
189
|
}
|
|
195
190
|
export {
|
|
196
191
|
g as a,
|
|
197
192
|
y as b,
|
|
198
193
|
j as c,
|
|
199
|
-
d,
|
|
194
|
+
w as d,
|
|
200
195
|
T as e,
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
i as g,
|
|
197
|
+
d as i,
|
|
203
198
|
p as m
|
|
204
199
|
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terrain (spec: "Terrain") — 3D elevation surface + per-layer draping,
|
|
3
|
+
* declared as `terrain*` attributes on <om-map> (the basemap=/lighting=
|
|
4
|
+
* scene-attribute precedent: free undo/redo, live MutationObserver
|
|
5
|
+
* switching).
|
|
6
|
+
*
|
|
7
|
+
* <om-map terrain="terrarium" terrain-exaggeration="1.5" pitch="55">
|
|
8
|
+
* <om-map terrain="https://tiles.example.com/dem/{z}/{x}/{y}.png"
|
|
9
|
+
* terrain-decoder="terrarium" terrain-max-zoom="14"
|
|
10
|
+
* terrain-texture="https://…/satellite/{z}/{x}/{y}.jpg">
|
|
11
|
+
*
|
|
12
|
+
* The seventh plugin registry (`OmMap.registerTerrain`) resolves preset
|
|
13
|
+
* names; a `{z}/{x}/{y}` URL is bring-your-own DEM (requires
|
|
14
|
+
* terrain-decoder). Geographic layers DRAPE onto the surface by default;
|
|
15
|
+
* a per-layer `terrain="drape|offset|off"` attribute overrides (3D-model
|
|
16
|
+
* layers default to `offset` — models sit ON terrain, not painted onto
|
|
17
|
+
* it).
|
|
18
|
+
*
|
|
19
|
+
* Terrain REPLACES an active basemap: a flat MapLibre canvas sits at sea
|
|
20
|
+
* level and visibly desyncs from a raised surface (true coexistence is
|
|
21
|
+
* the interleaved-compositing TODO). RuntimeCore suppresses the basemap
|
|
22
|
+
* while terrain is active and restores it when terrain turns off.
|
|
23
|
+
*
|
|
24
|
+
* `applyTerrain` is PURE (unit-testable without a GPU — headless never
|
|
25
|
+
* reaches the deck handoff): it computes each layer's terrain patches and
|
|
26
|
+
* the terrain-surface layer props; RuntimeCore feeds them to buildLayers.
|
|
27
|
+
*/
|
|
28
|
+
import type { Layer } from "@deck.gl/core";
|
|
29
|
+
import type { LayerIR } from "./ir";
|
|
30
|
+
/** RGB DEM decoder: height = offset + R·rScaler + G·gScaler + B·bScaler. */
|
|
31
|
+
export interface ElevationDecoder {
|
|
32
|
+
rScaler: number;
|
|
33
|
+
gScaler: number;
|
|
34
|
+
bScaler: number;
|
|
35
|
+
offset: number;
|
|
36
|
+
}
|
|
37
|
+
export declare const DECODERS: Readonly<Record<string, ElevationDecoder>>;
|
|
38
|
+
export interface TerrainPreset {
|
|
39
|
+
/** `{z}/{x}/{y}` DEM tile URL template (may carry a `{key}` placeholder for keyed providers). */
|
|
40
|
+
elevationData: string;
|
|
41
|
+
/** Decoder name ("terrarium" / "mapbox-rgb") or explicit scalers. */
|
|
42
|
+
decoder: keyof typeof DECODERS | ElevationDecoder;
|
|
43
|
+
/**
|
|
44
|
+
* The provider's REAL tileset cap — deck over-samples past it for closer
|
|
45
|
+
* cameras; a too-high cap requests tiles that 404 and blanks the terrain.
|
|
46
|
+
*/
|
|
47
|
+
maxZoom: number;
|
|
48
|
+
/** Optional draped imagery `{z}/{x}/{y}` URL template. */
|
|
49
|
+
texture?: string;
|
|
50
|
+
/** Display name (switcher UIs). */
|
|
51
|
+
label?: string;
|
|
52
|
+
/** Which key `{key}` substitutes — the basemap-registry convention. */
|
|
53
|
+
requiresKey?: "maptiler";
|
|
54
|
+
}
|
|
55
|
+
export declare function registerTerrain(name: string, preset: TerrainPreset): void;
|
|
56
|
+
export declare function getTerrain(name: string): TerrainPreset | undefined;
|
|
57
|
+
export declare function getAllTerrains(): ReadonlyMap<string, TerrainPreset>;
|
|
58
|
+
export interface TerrainIR {
|
|
59
|
+
elevationData: string;
|
|
60
|
+
elevationDecoder: ElevationDecoder;
|
|
61
|
+
maxZoom: number;
|
|
62
|
+
/** Multiplies decoded DEM heights (1 = true relief). */
|
|
63
|
+
exaggeration: number;
|
|
64
|
+
texture?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ResolvedTerrain {
|
|
67
|
+
ir: TerrainIR | null;
|
|
68
|
+
/** Resolution problem (unknown preset / missing key / missing decoder) — the caller decides how loudly to fail; `ir` is null when unresolvable. */
|
|
69
|
+
error?: string;
|
|
70
|
+
}
|
|
71
|
+
/** Is this `terrain` value a bring-your-own DEM URL rather than a preset name? (The basemap isStyleUrl convention.) */
|
|
72
|
+
export declare function isDemUrl(raw: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* `terrain*` attributes → TerrainIR. Returns `{ir: null}` when `terrain`
|
|
75
|
+
* is absent/"off"; `{ir: null, error}` when set but unresolvable (unknown
|
|
76
|
+
* preset, keyless keyed preset, raw URL without a decoder) — terrain
|
|
77
|
+
* renders NOTHING in that case rather than a wrong surface, and validation
|
|
78
|
+
* carries the loud version of the same message.
|
|
79
|
+
*/
|
|
80
|
+
export declare function parseTerrainAttrs(getAttr: (name: string) => string | null, maptilerKey?: string): ResolvedTerrain;
|
|
81
|
+
export declare const TERRAIN_LAYER_ID = "__onlymapjs-terrain";
|
|
82
|
+
export type LayerTerrainMode = "drape" | "offset" | "off";
|
|
83
|
+
export declare const LAYER_TERRAIN_MODES: readonly ["drape", "offset", "off"];
|
|
84
|
+
export declare function defaultTerrainMode(type: string): LayerTerrainMode;
|
|
85
|
+
export interface TerrainLayerPatch {
|
|
86
|
+
/**
|
|
87
|
+
* The deck-layer id to construct with. Suffixed `#t<generation>` while
|
|
88
|
+
* terrain is active: adding/removing an extension on a LIVE layer
|
|
89
|
+
* recompiles shaders and corrupts attribute state (the DataFilterExtension
|
|
90
|
+
* birth-mount rule), and a stale TerrainExtension vertical offset survives
|
|
91
|
+
* a terrain toggle on a stable id — a fresh id forces clean teardown +
|
|
92
|
+
* rebuild. RuntimeCore maps these generated ids back to authored ids for
|
|
93
|
+
* picks without guessing from the string shape.
|
|
94
|
+
*/
|
|
95
|
+
deckId: string;
|
|
96
|
+
/** Extra constructor props: extensions (APPENDED to existing — DataFilterExtension stays mounted) + terrainDrawMode. Empty for mode "off". */
|
|
97
|
+
extraProps: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Per-layer terrain patches, PURE. `terrainActive` false → identity patches
|
|
101
|
+
* (stable ids, no props). Runtime-internal layers (trace temps, draw
|
|
102
|
+
* preview, tooltip plumbing) never drape — they're screen-space/transient.
|
|
103
|
+
*/
|
|
104
|
+
export declare function applyTerrain(irs: readonly LayerIR[], terrainActive: boolean, generation: number): Map<string, TerrainLayerPatch>;
|
|
105
|
+
/**
|
|
106
|
+
* The terrain-surface layer itself. `operation: "terrain+draw"` makes it
|
|
107
|
+
* double as the elevation surface extension-carrying layers drape onto;
|
|
108
|
+
* `pickable: "3d"` runs the depth pick pass so click/hover coordinates
|
|
109
|
+
* unproject at the SURFACE's depth instead of z=0 sea level (without it,
|
|
110
|
+
* tilted-view picks/drawn vertices land behind the cursor). Exempt from
|
|
111
|
+
* license gates by the `__onlymapjs-` prefix.
|
|
112
|
+
*/
|
|
113
|
+
export declare function buildTerrainLayer(ir: TerrainIR): Layer;
|
package/dist/version.d.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { decompress as r } from "./index-2v2NXF_n.js";
|
|
2
|
+
async function o(t) {
|
|
3
|
+
const e = r(new Uint8Array(t));
|
|
4
|
+
return n(e);
|
|
5
|
+
}
|
|
6
|
+
function n(t) {
|
|
7
|
+
if (t.byteOffset === 0 && t.byteLength === t.buffer.byteLength)
|
|
8
|
+
return t.buffer;
|
|
9
|
+
const e = new Uint8Array(t.byteLength);
|
|
10
|
+
return e.set(t), e.buffer;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
o as decode
|
|
14
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Registering an external layer class
|
|
2
|
+
|
|
3
|
+
`OmMap.registerLayer` makes any deck.gl layer class a first-class manifest
|
|
4
|
+
type: validation, IntelliSense generation, and attribute resolution all read
|
|
5
|
+
the same schema the built-ins use. This page is the recipe for bringing a
|
|
6
|
+
layer class the library doesn't bundle — a community layer, a company shim, a
|
|
7
|
+
composite that wraps a whole data pipeline.
|
|
8
|
+
|
|
9
|
+
## Rule 1: build on `@nika-js/onlymap/deck`, never on your own deck.gl
|
|
10
|
+
|
|
11
|
+
OnlyMapJS bundles deck.gl (it has zero runtime dependencies). If your class
|
|
12
|
+
extends a `@deck.gl/*` copy you installed yourself, it belongs to a
|
|
13
|
+
**different class hierarchy** — two `Layer` base classes, two luma.gl
|
|
14
|
+
runtimes — and fails inside the bundled renderer. The `deck` subpath
|
|
15
|
+
re-exports the bundled classes, so your shim extends the exact objects the
|
|
16
|
+
core renders with:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import { CompositeLayer, TileLayer, BitmapLayer } from "@nika-js/onlymap/deck";
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Available: `Layer`, `CompositeLayer`, `LayerExtension`, `WebMercatorViewport`,
|
|
23
|
+
`COORDINATE_SYSTEM`, `GeoJsonLayer`, `ScatterplotLayer`, `IconLayer`,
|
|
24
|
+
`BitmapLayer`, `TileLayer`, `Tile3DLayer`, `SimpleMeshLayer`,
|
|
25
|
+
`ScenegraphLayer` — plus authoring types (`LayerProps`, `DefaultProps`,
|
|
26
|
+
`UpdateParameters`, `PickingInfo`, `LayersList`; typechecking against them
|
|
27
|
+
needs `@deck.gl/core` as a dev dependency).
|
|
28
|
+
|
|
29
|
+
## Rule 2: functions ride `static defaultProps`, not attributes
|
|
30
|
+
|
|
31
|
+
HTML attributes are strings — function-valued props (`renderSubLayers`,
|
|
32
|
+
`getTileData`, load callbacks) are inexpressible by design. Put them on a
|
|
33
|
+
thin subclass; deck.gl's own defaultProps merge delivers them to every
|
|
34
|
+
instance:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
class CogLayer extends CompositeLayer {
|
|
38
|
+
static layerName = "CogLayer";
|
|
39
|
+
static defaultProps = {
|
|
40
|
+
renderTile: { type: "function", value: renderTile },
|
|
41
|
+
onRasterLoad: { type: "function", value: () => {} },
|
|
42
|
+
};
|
|
43
|
+
renderLayers() {
|
|
44
|
+
/* compose TileLayer/BitmapLayer from the subpath here */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rule 3: the schema wires attributes to deck props
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { OmMap } from "@nika-js/onlymap";
|
|
53
|
+
|
|
54
|
+
OmMap.registerLayer({
|
|
55
|
+
type: "CogLayer",
|
|
56
|
+
deckClass: CogLayer,
|
|
57
|
+
props: [
|
|
58
|
+
// deck's URL prop is `data`, but OnlyMapJS reserves the `data` attribute
|
|
59
|
+
// for its own loader — alias it, and the layer class fetches for itself
|
|
60
|
+
// (the built-in Tile3DLayer `tileset` attribute uses the same trick).
|
|
61
|
+
{ attr: "src", kind: "scalar", deckProp: "data", type: "string", required: true },
|
|
62
|
+
// JSON attributes and dot-path descriptors compose: the JSON sets the
|
|
63
|
+
// object, later dot-paths merge into it.
|
|
64
|
+
{ attr: "load-options", kind: "scalar", deckProp: "loadOptions", type: "json" },
|
|
65
|
+
{ attr: "max-error", kind: "scalar", deckProp: "loadOptions.cog.maxError", type: "number" },
|
|
66
|
+
{ attr: "opacity", kind: "scalar", deckProp: "opacity", type: "number", default: 1 },
|
|
67
|
+
{ attr: "visible", kind: "scalar", deckProp: "visible", type: "boolean", default: true },
|
|
68
|
+
// accessor-kind props get the full expression language:
|
|
69
|
+
// { attr: "get-color", kind: "accessor", deckProp: "getColor" },
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Then the manifest just works:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<om-layer id="rast" type="CogLayer" src="https://example.com/landcover.tif"
|
|
78
|
+
max-error="16" opacity="0.9"></om-layer>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Rule 4: register before the manifest mounts
|
|
82
|
+
|
|
83
|
+
Registration after mount does not retrigger reconciles — an unknown-type
|
|
84
|
+
layer is warn-skipped until the next DOM mutation. Call `registerLayer` at
|
|
85
|
+
module top level (the `registerSource`/`registerFormat` convention), before
|
|
86
|
+
the `<om-map>` connects.
|
|
87
|
+
|
|
88
|
+
## Verifying without a GPU
|
|
89
|
+
|
|
90
|
+
`OmMap.snapshotIR(html)` resolves your registered type through the same
|
|
91
|
+
pipeline the live reconciler runs — assert the aliased URL lands on
|
|
92
|
+
`props.data`, dot-paths nest, functions appear as `[function]` — in plain
|
|
93
|
+
jsdom/happy-dom, no WebGL.
|
|
94
|
+
|
|
95
|
+
## The programmatic alternative
|
|
96
|
+
|
|
97
|
+
On the `MapController` front-end (and the React adapter), `props` passes
|
|
98
|
+
function values directly — no subclass needed. The subclass recipe exists so
|
|
99
|
+
the **manifest** front-end can express what attributes can't.
|