@faclon-labs/app-sdk 0.1.0 → 0.3.0
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 +39 -1
- package/dist/IOSenseApp.js +26 -6
- package/dist/SignIn.js +2 -2
- package/dist/auth.d.ts +7 -0
- package/dist/auth.js +35 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/map/globe.d.ts +5 -0
- package/dist/map/globe.js +5 -0
- package/dist/map/index.d.ts +21 -0
- package/dist/map/index.js +21 -0
- package/dist/map/source.d.ts +48 -0
- package/dist/map/source.js +73 -0
- package/dist/map/testing.d.ts +5 -0
- package/dist/map/testing.js +5 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/package.json +55 -5
- package/vendor/SOURCE.txt +1 -0
- package/vendor/map-engine/cesium/camera.d.ts +10 -0
- package/vendor/map-engine/cesium/camera.js +25 -0
- package/vendor/map-engine/cesium/index.d.ts +2 -0
- package/vendor/map-engine/cesium/index.js +2 -0
- package/vendor/map-engine/cesium/renderer.d.ts +149 -0
- package/vendor/map-engine/cesium/renderer.js +837 -0
- package/vendor/map-engine/commands/index.d.ts +2 -0
- package/vendor/map-engine/commands/index.js +2 -0
- package/vendor/map-engine/commands/post-message.d.ts +32 -0
- package/vendor/map-engine/commands/post-message.js +77 -0
- package/vendor/map-engine/commands/webmcp.d.ts +17 -0
- package/vendor/map-engine/commands/webmcp.js +59 -0
- package/vendor/map-engine/core/commands.d.ts +82 -0
- package/vendor/map-engine/core/commands.js +46 -0
- package/vendor/map-engine/core/emitter.d.ts +9 -0
- package/vendor/map-engine/core/emitter.js +38 -0
- package/vendor/map-engine/core/equal.d.ts +2 -0
- package/vendor/map-engine/core/equal.js +28 -0
- package/vendor/map-engine/core/errors.d.ts +20 -0
- package/vendor/map-engine/core/errors.js +34 -0
- package/vendor/map-engine/core/geometry-family.d.ts +3 -0
- package/vendor/map-engine/core/geometry-family.js +13 -0
- package/vendor/map-engine/core/index.d.ts +4 -0
- package/vendor/map-engine/core/index.js +3 -0
- package/vendor/map-engine/core/types.d.ts +709 -0
- package/vendor/map-engine/core/types.js +7 -0
- package/vendor/map-engine/data/annotations.d.ts +3 -0
- package/vendor/map-engine/data/annotations.js +63 -0
- package/vendor/map-engine/data/contracts.d.ts +172 -0
- package/vendor/map-engine/data/contracts.js +12 -0
- package/vendor/map-engine/data/index.d.ts +4 -0
- package/vendor/map-engine/data/index.js +3 -0
- package/vendor/map-engine/data/schema.d.ts +7 -0
- package/vendor/map-engine/data/schema.js +40 -0
- package/vendor/map-engine/geofence/evaluator.d.ts +35 -0
- package/vendor/map-engine/geofence/evaluator.js +172 -0
- package/vendor/map-engine/geofence/history.d.ts +9 -0
- package/vendor/map-engine/geofence/history.js +19 -0
- package/vendor/map-engine/geofence/index.d.ts +2 -0
- package/vendor/map-engine/geofence/index.js +2 -0
- package/vendor/map-engine/index.d.ts +27 -0
- package/vendor/map-engine/index.js +14 -0
- package/vendor/map-engine/layers/index.d.ts +1 -0
- package/vendor/map-engine/layers/index.js +1 -0
- package/vendor/map-engine/layers/layers.d.ts +49 -0
- package/vendor/map-engine/layers/layers.js +316 -0
- package/vendor/map-engine/maplibre/deck-host.d.ts +105 -0
- package/vendor/map-engine/maplibre/deck-host.js +401 -0
- package/vendor/map-engine/maplibre/icons.d.ts +17 -0
- package/vendor/map-engine/maplibre/icons.js +65 -0
- package/vendor/map-engine/maplibre/index.d.ts +3 -0
- package/vendor/map-engine/maplibre/index.js +2 -0
- package/vendor/map-engine/maplibre/map-like.d.ts +56 -0
- package/vendor/map-engine/maplibre/map-like.js +1 -0
- package/vendor/map-engine/maplibre/renderer.d.ts +173 -0
- package/vendor/map-engine/maplibre/renderer.js +889 -0
- package/vendor/map-engine/maplibre/style.d.ts +84 -0
- package/vendor/map-engine/maplibre/style.js +493 -0
- package/vendor/map-engine/present/decorations.d.ts +25 -0
- package/vendor/map-engine/present/decorations.js +115 -0
- package/vendor/map-engine/present/index.d.ts +2 -0
- package/vendor/map-engine/present/index.js +2 -0
- package/vendor/map-engine/present/present.d.ts +47 -0
- package/vendor/map-engine/present/present.js +149 -0
- package/vendor/map-engine/query/index.d.ts +1 -0
- package/vendor/map-engine/query/index.js +1 -0
- package/vendor/map-engine/query/planner.d.ts +26 -0
- package/vendor/map-engine/query/planner.js +47 -0
- package/vendor/map-engine/react/MapView.d.ts +87 -0
- package/vendor/map-engine/react/MapView.js +270 -0
- package/vendor/map-engine/react/context.d.ts +39 -0
- package/vendor/map-engine/react/context.js +94 -0
- package/vendor/map-engine/react/index.d.ts +2 -0
- package/vendor/map-engine/react/index.js +2 -0
- package/vendor/map-engine/react/store.d.ts +19 -0
- package/vendor/map-engine/react/store.js +18 -0
- package/vendor/map-engine/realtime/apply.d.ts +74 -0
- package/vendor/map-engine/realtime/apply.js +155 -0
- package/vendor/map-engine/realtime/index.d.ts +1 -0
- package/vendor/map-engine/realtime/index.js +1 -0
- package/vendor/map-engine/render/index.d.ts +1 -0
- package/vendor/map-engine/render/index.js +1 -0
- package/vendor/map-engine/render/offline.d.ts +8 -0
- package/vendor/map-engine/render/offline.js +47 -0
- package/vendor/map-engine/render/renderer.d.ts +74 -0
- package/vendor/map-engine/render/renderer.js +1 -0
- package/vendor/map-engine/render/terrarium.d.ts +48 -0
- package/vendor/map-engine/render/terrarium.js +110 -0
- package/vendor/map-engine/runtime/drawing.d.ts +28 -0
- package/vendor/map-engine/runtime/drawing.js +58 -0
- package/vendor/map-engine/runtime/index.d.ts +5 -0
- package/vendor/map-engine/runtime/index.js +2 -0
- package/vendor/map-engine/runtime/offline.d.ts +24 -0
- package/vendor/map-engine/runtime/offline.js +37 -0
- package/vendor/map-engine/runtime/overlays.d.ts +25 -0
- package/vendor/map-engine/runtime/overlays.js +65 -0
- package/vendor/map-engine/runtime/runtime.d.ts +4 -0
- package/vendor/map-engine/runtime/runtime.js +2105 -0
- package/vendor/map-engine/runtime/types.d.ts +407 -0
- package/vendor/map-engine/runtime/types.js +1 -0
- package/vendor/map-engine/scene/index.d.ts +1 -0
- package/vendor/map-engine/scene/index.js +1 -0
- package/vendor/map-engine/scene/scene.d.ts +31 -0
- package/vendor/map-engine/scene/scene.js +216 -0
- package/vendor/map-engine/selection/index.d.ts +1 -0
- package/vendor/map-engine/selection/index.js +1 -0
- package/vendor/map-engine/selection/selection.d.ts +12 -0
- package/vendor/map-engine/selection/selection.js +28 -0
- package/vendor/map-engine/spatial/geojson.d.ts +15 -0
- package/vendor/map-engine/spatial/geojson.js +83 -0
- package/vendor/map-engine/spatial/geometry.d.ts +13 -0
- package/vendor/map-engine/spatial/geometry.js +206 -0
- package/vendor/map-engine/spatial/import.d.ts +27 -0
- package/vendor/map-engine/spatial/import.js +96 -0
- package/vendor/map-engine/spatial/index.d.ts +38 -0
- package/vendor/map-engine/spatial/index.js +37 -0
- package/vendor/map-engine/spatial/line-of-sight.d.ts +35 -0
- package/vendor/map-engine/spatial/line-of-sight.js +43 -0
- package/vendor/map-engine/spatial/measure.d.ts +28 -0
- package/vendor/map-engine/spatial/measure.js +90 -0
- package/vendor/map-engine/spatial/operations.d.ts +21 -0
- package/vendor/map-engine/spatial/operations.js +171 -0
- package/vendor/map-engine/spatial/query.d.ts +17 -0
- package/vendor/map-engine/spatial/query.js +88 -0
- package/vendor/map-engine/spatial/spatial-index.d.ts +24 -0
- package/vendor/map-engine/spatial/spatial-index.js +36 -0
- package/vendor/map-engine/spatial/volume-mesh.d.ts +19 -0
- package/vendor/map-engine/spatial/volume-mesh.js +56 -0
- package/vendor/map-engine/temporal/index.d.ts +3 -0
- package/vendor/map-engine/temporal/index.js +3 -0
- package/vendor/map-engine/temporal/journal.d.ts +20 -0
- package/vendor/map-engine/temporal/journal.js +34 -0
- package/vendor/map-engine/temporal/playback.d.ts +41 -0
- package/vendor/map-engine/temporal/playback.js +80 -0
- package/vendor/map-engine/temporal/tracks.d.ts +33 -0
- package/vendor/map-engine/temporal/tracks.js +119 -0
- package/vendor/map-engine/testing/annotation-store.d.ts +24 -0
- package/vendor/map-engine/testing/annotation-store.js +43 -0
- package/vendor/map-engine/testing/contracts.d.ts +41 -0
- package/vendor/map-engine/testing/contracts.js +328 -0
- package/vendor/map-engine/testing/fixtures-monitoring.d.ts +22 -0
- package/vendor/map-engine/testing/fixtures-monitoring.js +103 -0
- package/vendor/map-engine/testing/fixtures.d.ts +18 -0
- package/vendor/map-engine/testing/fixtures.js +28 -0
- package/vendor/map-engine/testing/index.d.ts +7 -0
- package/vendor/map-engine/testing/index.js +7 -0
- package/vendor/map-engine/testing/mock-ontology.d.ts +13 -0
- package/vendor/map-engine/testing/mock-ontology.js +24 -0
- package/vendor/map-engine/testing/mock-provider.d.ts +97 -0
- package/vendor/map-engine/testing/mock-provider.js +369 -0
- package/vendor/map-engine/testing/test-renderer.d.ts +72 -0
- package/vendor/map-engine/testing/test-renderer.js +153 -0
- package/vendor/map-engine/viewport/index.d.ts +1 -0
- package/vendor/map-engine/viewport/index.js +1 -0
- package/vendor/map-engine/viewport/viewport.d.ts +19 -0
- package/vendor/map-engine/viewport/viewport.js +102 -0
- package/vendor/map-provider-uns/client.d.ts +75 -0
- package/vendor/map-provider-uns/client.js +111 -0
- package/vendor/map-provider-uns/index.d.ts +2 -0
- package/vendor/map-provider-uns/index.js +2 -0
- package/vendor/map-provider-uns/provider.d.ts +131 -0
- package/vendor/map-provider-uns/provider.js +561 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { circlePolygon, destination, ellipsePolygon, sectorPolygon } from '../spatial/measure.js';
|
|
2
|
+
import { labelPoint } from '../spatial/operations.js';
|
|
3
|
+
/** Engine layer ids are `__deco~<layerId>~<part>`; the part says what it draws. */
|
|
4
|
+
export const DECO_PREFIX = '__deco~';
|
|
5
|
+
const PARTS = ['footprint', 'uncertainty', 'alt-lines', 'alt-points', 'rings'];
|
|
6
|
+
export const decoLayerId = (layerId, part) => `${DECO_PREFIX}${layerId}~${part}`;
|
|
7
|
+
/** The application layer and object a decoration belongs to (for picking), or null for any other layer. */
|
|
8
|
+
export function decorationOwner(layerId, objectId) {
|
|
9
|
+
if (!layerId.startsWith(DECO_PREFIX))
|
|
10
|
+
return null;
|
|
11
|
+
const rest = layerId.slice(DECO_PREFIX.length);
|
|
12
|
+
const cut = rest.lastIndexOf('~');
|
|
13
|
+
if (cut < 0)
|
|
14
|
+
return null;
|
|
15
|
+
const tilde = objectId.indexOf('~');
|
|
16
|
+
return { layerId: rest.slice(0, cut), objectId: tilde < 0 ? objectId : objectId.slice(0, tilde) };
|
|
17
|
+
}
|
|
18
|
+
const UNCERTAIN = '#7A3FD6';
|
|
19
|
+
/** The engine layers a layer's decorations need (none when it has no decoration options). */
|
|
20
|
+
export function decorationLayers(layer) {
|
|
21
|
+
const vz = layer.visualization;
|
|
22
|
+
const base = { source: {}, visible: layer.visible, interaction: { selectable: layer.interaction?.selectable !== false, hoverable: false } };
|
|
23
|
+
const z = (k) => layer.zIndex - 0.001 * k;
|
|
24
|
+
const out = [];
|
|
25
|
+
if (vz.footprint) {
|
|
26
|
+
const c = vz.footprint.color ?? '#0E9AA7';
|
|
27
|
+
out.push({ ...base, id: decoLayerId(layer.id, 'footprint'), zIndex: z(4), visualization: { type: 'polygon', style: [{ style: { color: c, opacity: 0.14, strokeColor: c, strokeWidth: 1 } }] } });
|
|
28
|
+
}
|
|
29
|
+
if (vz.uncertainty) {
|
|
30
|
+
const c = vz.uncertainty.color ?? UNCERTAIN;
|
|
31
|
+
out.push({ ...base, id: decoLayerId(layer.id, 'uncertainty'), zIndex: z(3), visualization: { type: 'polygon', style: [{ style: { color: c, opacity: vz.uncertainty.opacity ?? 0.15, strokeColor: c, strokeWidth: 1, dash: [2, 1.5] } }] } });
|
|
32
|
+
if (vz.uncertainty.alternatives !== false) {
|
|
33
|
+
out.push({ ...base, id: decoLayerId(layer.id, 'alt-lines'), zIndex: z(2), visualization: { type: 'line', style: [{ style: { color: c, size: 1.5, opacity: 0.8, dash: [2, 2] } }] } });
|
|
34
|
+
out.push({ ...base, id: decoLayerId(layer.id, 'alt-points'), zIndex: z(1), visualization: { type: 'marker', style: [{ style: { color: '#FFFFFF', size: 5, strokeColor: c, strokeWidth: 2 } }], label: { property: 'label', size: 10 } } });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (vz.rings) {
|
|
38
|
+
const c = vz.rings.color ?? '#475569';
|
|
39
|
+
out.push({ ...base, id: decoLayerId(layer.id, 'rings'), zIndex: z(5), interaction: { selectable: false, hoverable: false }, visualization: { type: 'line', style: [{ style: { color: c, size: 1, opacity: 0.7, dash: [3, 2] } }], ...(vz.rings.labels !== false ? { label: { property: 'label', size: 10 } } : {}) } });
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
const num = (v) => {
|
|
44
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' && v.trim() !== '' ? Number(v) : Number.NaN;
|
|
45
|
+
return Number.isFinite(n) ? n : undefined;
|
|
46
|
+
};
|
|
47
|
+
export const formatDistance = (m) => (m >= 1000 ? `${Number((m / 1000).toFixed(m % 1000 === 0 ? 0 : 1))} km` : `${Math.round(m)} m`);
|
|
48
|
+
/** The ground area a camera sees (FootprintConfig); null without a heading. */
|
|
49
|
+
export function footprintOf(f, at, props) {
|
|
50
|
+
const heading = num(props?.[f.headingProperty]);
|
|
51
|
+
if (heading === undefined)
|
|
52
|
+
return null;
|
|
53
|
+
const pitch = num(f.pitchProperty ? props?.[f.pitchProperty] : undefined) ?? f.pitch ?? 30;
|
|
54
|
+
const hfov = Math.max(1, Math.min(170, num(f.fovProperty ? props?.[f.fovProperty] : undefined) ?? f.fov ?? 40));
|
|
55
|
+
const vfov = Math.max(1, Math.min(170, f.fovVertical ?? hfov * 0.75));
|
|
56
|
+
const height = num(f.heightProperty ? props?.[f.heightProperty] : undefined) ?? f.height;
|
|
57
|
+
const maxR = f.maxRangeMeters ?? 5000;
|
|
58
|
+
if (!(height !== undefined && height > 0))
|
|
59
|
+
return sectorPolygon(at, heading - hfov / 2, heading + hfov / 2, 0, maxR);
|
|
60
|
+
const rad = (d) => (d * Math.PI) / 180;
|
|
61
|
+
const lower = pitch + vfov / 2; // the ray to the bottom of the picture
|
|
62
|
+
const upper = pitch - vfov / 2; // the ray to the top
|
|
63
|
+
const near = lower >= 89.9 ? 0 : Math.min(maxR, height / Math.tan(rad(lower)));
|
|
64
|
+
const far = upper <= 0.1 ? maxR : Math.min(maxR, height / Math.tan(rad(upper)));
|
|
65
|
+
if (!(far > near))
|
|
66
|
+
return null;
|
|
67
|
+
// Rays to the picture's left and right edges run longer than the centre ray.
|
|
68
|
+
const side = (d) => d / Math.cos(rad(hfov / 2));
|
|
69
|
+
const corner = (d, sign) => (d <= 0 ? at : destination(at, heading + (sign * hfov) / 2, side(d)));
|
|
70
|
+
const pts = [corner(near, -1), corner(near, 1), corner(far, 1), corner(far, -1)];
|
|
71
|
+
return { type: 'Polygon', coordinates: [[...pts, pts[0]]] };
|
|
72
|
+
}
|
|
73
|
+
/** Decoration objects per engine layer, for a layer's (presented) objects. */
|
|
74
|
+
export function decorationObjects(layer, objects) {
|
|
75
|
+
const vz = layer.visualization;
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const l of decorationLayers(layer))
|
|
78
|
+
out[l.id] = [];
|
|
79
|
+
if (!Object.keys(out).length)
|
|
80
|
+
return out;
|
|
81
|
+
for (const o of objects) {
|
|
82
|
+
if (o.geometry.type !== 'Point')
|
|
83
|
+
continue;
|
|
84
|
+
const at = o.geometry.coordinates;
|
|
85
|
+
if (vz.footprint) {
|
|
86
|
+
const g = footprintOf(vz.footprint, at, o.properties);
|
|
87
|
+
if (g)
|
|
88
|
+
out[decoLayerId(layer.id, 'footprint')].push({ objectId: o.objectId, geometry: g });
|
|
89
|
+
}
|
|
90
|
+
if (vz.uncertainty) {
|
|
91
|
+
const u = o.uncertainty;
|
|
92
|
+
const g = u?.ellipse && u.ellipse.semiMajorMeters > 0 && u.ellipse.semiMinorMeters > 0 ? ellipsePolygon(at, u.ellipse.semiMajorMeters, u.ellipse.semiMinorMeters, u.ellipse.orientationDegrees ?? 0) : u?.radiusMeters && u.radiusMeters > 0 ? circlePolygon(at, u.radiusMeters) : null;
|
|
93
|
+
if (g)
|
|
94
|
+
out[decoLayerId(layer.id, 'uncertainty')].push({ objectId: o.objectId, geometry: g });
|
|
95
|
+
if (vz.uncertainty.alternatives !== false) {
|
|
96
|
+
(o.alternatives ?? []).forEach((alt, i) => {
|
|
97
|
+
const id = `${o.objectId}~${alt.id ?? i}`;
|
|
98
|
+
const p = alt.geometry.type === 'Point' ? alt.geometry.coordinates : labelPoint(alt.geometry);
|
|
99
|
+
const pct = alt.probability !== undefined ? ` ${Math.round(alt.probability * 100)}%` : '';
|
|
100
|
+
out[decoLayerId(layer.id, 'alt-points')].push({ objectId: id, geometry: { type: 'Point', coordinates: p }, properties: { label: `${alt.label ?? 'alternative'}${pct}` } });
|
|
101
|
+
out[decoLayerId(layer.id, 'alt-lines')].push({ objectId: id, geometry: { type: 'LineString', coordinates: [at, p] } });
|
|
102
|
+
if (alt.geometry.type === 'Polygon')
|
|
103
|
+
out[decoLayerId(layer.id, 'alt-lines')].push({ objectId: `${id}~outline`, geometry: { type: 'LineString', coordinates: alt.geometry.coordinates[0] } });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (vz.rings) {
|
|
108
|
+
vz.rings.distancesMeters.forEach((d, i) => {
|
|
109
|
+
const ring = circlePolygon(at, d, 72).coordinates[0];
|
|
110
|
+
out[decoLayerId(layer.id, 'rings')].push({ objectId: `${o.objectId}~r${i}`, geometry: { type: 'LineString', coordinates: ring }, properties: { label: formatDistance(d) } });
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { AGE, ALTERNATIVES, CONFIDENCE, ageOf, effectiveLayer, isValidAt, nextAgeChangeMs, presentObject, scaled, scaleValue, validatePresentation, type AgeState } from './present.js';
|
|
2
|
+
export { DECO_PREFIX, decorationLayers, decorationObjects, decorationOwner, footprintOf, formatDistance } from './decorations.js';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { AGE, ALTERNATIVES, CONFIDENCE, ageOf, effectiveLayer, isValidAt, nextAgeChangeMs, presentObject, scaled, scaleValue, validatePresentation } from './present.js';
|
|
2
|
+
export { DECO_PREFIX, decorationLayers, decorationObjects, decorationOwner, footprintOf, formatDistance } from './decorations.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation: what an object looks like to the scene at a time (doc 28 A, doc 29 §1–4). The runtime keeps the
|
|
3
|
+
* provider's object as it is (index, queries, inspect); the scene gets this view of it:
|
|
4
|
+
*
|
|
5
|
+
* - outside its validity window (`validFrom` … `validUntil`) it is not drawn;
|
|
6
|
+
* - `$age` from `observedAt` and the layer's age thresholds (live clock or replay time); it changes exactly when
|
|
7
|
+
* the state changes (the runtime schedules that moment), so a map of 10 000 objects is not redrawn every second;
|
|
8
|
+
* - `$confidence` from `object.confidence`; `$alternatives` = number of unresolved candidates;
|
|
9
|
+
* - `$s:<token>` = the value of each continuous scale (renderers read it before any rule).
|
|
10
|
+
*
|
|
11
|
+
* Rules and conditions can use these `$` properties like any other. Nothing here knows a domain.
|
|
12
|
+
*/
|
|
13
|
+
import type { AgeConfig, MapLayer, SpatialObject, StyleScale } from '../core/types.js';
|
|
14
|
+
export declare const AGE = "$age";
|
|
15
|
+
export declare const CONFIDENCE = "$confidence";
|
|
16
|
+
export declare const ALTERNATIVES = "$alternatives";
|
|
17
|
+
/** The per-object value of a continuous scale for a style token: `$s:opacity`, `$s:color`… */
|
|
18
|
+
export declare const scaled: (token: StyleScale["token"]) => string;
|
|
19
|
+
export type AgeState = 'fresh' | 'ageing' | 'stale' | 'lost';
|
|
20
|
+
/** Whether the object's state holds at `nowMs` (no window = always). */
|
|
21
|
+
export declare function isValidAt(o: SpatialObject, nowMs: number): boolean;
|
|
22
|
+
/** Age of an object at `nowMs` under the layer's thresholds; null when it does not age (no config or no time). */
|
|
23
|
+
export declare function ageOf(o: SpatialObject, age: AgeConfig | undefined, nowMs: number): {
|
|
24
|
+
state: AgeState;
|
|
25
|
+
seconds: number;
|
|
26
|
+
} | null;
|
|
27
|
+
/** The age state an object will next change to, in ms from now (for the clock tick), or null if it never will. */
|
|
28
|
+
export declare function nextAgeChangeMs(o: SpatialObject, age: AgeConfig | undefined, nowMs: number): number | null;
|
|
29
|
+
/** One scale's value for a property value; undefined when the value is not a number. */
|
|
30
|
+
export declare function scaleValue(scale: StyleScale, raw: unknown): number | string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* The scene's view of one object through one layer at `nowMs`; null when it is not drawn now (outside its
|
|
33
|
+
* validity window, or lost and the layer hides lost objects). The same object is returned when nothing applies.
|
|
34
|
+
*/
|
|
35
|
+
export declare function presentObject(layer: MapLayer, o: SpatialObject, nowMs: number): SpatialObject | null;
|
|
36
|
+
/**
|
|
37
|
+
* The layer as the renderer gets it: link layers draw as lines; age fading becomes leading rules on `$age`
|
|
38
|
+
* (rules are per token, so the fade sets opacity — or a dashed outline for areas — and colours fall through).
|
|
39
|
+
*/
|
|
40
|
+
export declare function effectiveLayer(layer: MapLayer): MapLayer;
|
|
41
|
+
/** Validates the presentation options of a layer (age, scales, decorations). */
|
|
42
|
+
export declare function validatePresentation(l: MapLayer): {
|
|
43
|
+
valid: true;
|
|
44
|
+
} | {
|
|
45
|
+
valid: false;
|
|
46
|
+
reason: string;
|
|
47
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
export const AGE = '$age';
|
|
2
|
+
export const CONFIDENCE = '$confidence';
|
|
3
|
+
export const ALTERNATIVES = '$alternatives';
|
|
4
|
+
/** The per-object value of a continuous scale for a style token: `$s:opacity`, `$s:color`… */
|
|
5
|
+
export const scaled = (token) => `$s:${token}`;
|
|
6
|
+
const ms = (iso) => (iso ? Date.parse(iso) : Number.NaN);
|
|
7
|
+
/** Whether the object's state holds at `nowMs` (no window = always). */
|
|
8
|
+
export function isValidAt(o, nowMs) {
|
|
9
|
+
const from = ms(o.validFrom);
|
|
10
|
+
const until = ms(o.validUntil);
|
|
11
|
+
return !(Number.isFinite(from) && nowMs < from) && !(Number.isFinite(until) && nowMs > until);
|
|
12
|
+
}
|
|
13
|
+
/** Age of an object at `nowMs` under the layer's thresholds; null when it does not age (no config or no time). */
|
|
14
|
+
export function ageOf(o, age, nowMs) {
|
|
15
|
+
if (!age)
|
|
16
|
+
return null;
|
|
17
|
+
const seen = ms(o.observedAt);
|
|
18
|
+
if (!Number.isFinite(seen))
|
|
19
|
+
return null;
|
|
20
|
+
const seconds = Math.max(0, (nowMs - seen) / 1000);
|
|
21
|
+
const ageing = age.ageingAfterSeconds ?? age.staleAfterSeconds / 2;
|
|
22
|
+
const state = age.lostAfterSeconds !== undefined && seconds >= age.lostAfterSeconds ? 'lost' : seconds >= age.staleAfterSeconds ? 'stale' : seconds >= ageing ? 'ageing' : 'fresh';
|
|
23
|
+
return { state, seconds: Math.floor(seconds) };
|
|
24
|
+
}
|
|
25
|
+
/** The age state an object will next change to, in ms from now (for the clock tick), or null if it never will. */
|
|
26
|
+
export function nextAgeChangeMs(o, age, nowMs) {
|
|
27
|
+
if (!age)
|
|
28
|
+
return null;
|
|
29
|
+
const seen = ms(o.observedAt);
|
|
30
|
+
if (!Number.isFinite(seen))
|
|
31
|
+
return null;
|
|
32
|
+
const marks = [age.ageingAfterSeconds ?? age.staleAfterSeconds / 2, age.staleAfterSeconds, age.lostAfterSeconds].filter((x) => x !== undefined);
|
|
33
|
+
const next = marks.map((s) => seen + s * 1000 - nowMs).filter((d) => d > 0);
|
|
34
|
+
return next.length ? Math.min(...next) : null;
|
|
35
|
+
}
|
|
36
|
+
const HEX = /^#([0-9a-f]{6})$/i;
|
|
37
|
+
function mixColor(a, b, t) {
|
|
38
|
+
const pa = HEX.exec(a)?.[1];
|
|
39
|
+
const pb = HEX.exec(b)?.[1];
|
|
40
|
+
if (!pa || !pb)
|
|
41
|
+
return t < 0.5 ? a : b;
|
|
42
|
+
const ch = (h, i) => parseInt(h.slice(i, i + 2), 16);
|
|
43
|
+
const out = [0, 2, 4].map((i) => Math.round(ch(pa, i) + (ch(pb, i) - ch(pa, i)) * t).toString(16).padStart(2, '0'));
|
|
44
|
+
return `#${out.join('').toUpperCase()}`;
|
|
45
|
+
}
|
|
46
|
+
/** One scale's value for a property value; undefined when the value is not a number. */
|
|
47
|
+
export function scaleValue(scale, raw) {
|
|
48
|
+
const n = typeof raw === 'number' ? raw : typeof raw === 'string' && raw.trim() !== '' ? Number(raw) : Number.NaN;
|
|
49
|
+
if (!Number.isFinite(n))
|
|
50
|
+
return undefined;
|
|
51
|
+
const [d0, d1] = scale.domain;
|
|
52
|
+
const t = d1 === d0 ? 1 : Math.max(0, Math.min(1, (n - d0) / (d1 - d0)));
|
|
53
|
+
const [r0, r1] = scale.range;
|
|
54
|
+
if (typeof r0 === 'string' || typeof r1 === 'string')
|
|
55
|
+
return mixColor(String(r0), String(r1), t);
|
|
56
|
+
return r0 + (r1 - r0) * t;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The scene's view of one object through one layer at `nowMs`; null when it is not drawn now (outside its
|
|
60
|
+
* validity window, or lost and the layer hides lost objects). The same object is returned when nothing applies.
|
|
61
|
+
*/
|
|
62
|
+
export function presentObject(layer, o, nowMs) {
|
|
63
|
+
if (!isValidAt(o, nowMs))
|
|
64
|
+
return null;
|
|
65
|
+
const vz = layer.visualization;
|
|
66
|
+
const age = vz.type === 'track' ? null : ageOf(o, vz.age, nowMs);
|
|
67
|
+
if (age?.state === 'lost' && vz.age?.hideLost)
|
|
68
|
+
return null;
|
|
69
|
+
const extra = {};
|
|
70
|
+
if (age)
|
|
71
|
+
extra[AGE] = age.state;
|
|
72
|
+
if (typeof o.confidence === 'number' && Number.isFinite(o.confidence))
|
|
73
|
+
extra[CONFIDENCE] = o.confidence;
|
|
74
|
+
if (o.alternatives?.length)
|
|
75
|
+
extra[ALTERNATIVES] = o.alternatives.length;
|
|
76
|
+
if (vz.scales?.length) {
|
|
77
|
+
const props = { ...o.properties, ...extra };
|
|
78
|
+
for (const s of vz.scales) {
|
|
79
|
+
const v = scaleValue(s, props[s.property]);
|
|
80
|
+
if (v !== undefined)
|
|
81
|
+
extra[scaled(s.token)] = v;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return Object.keys(extra).length ? { ...o, properties: { ...o.properties, ...extra } } : o;
|
|
85
|
+
}
|
|
86
|
+
const FADE = { ageing: 0.7, stale: 0.4, lost: 0.2 };
|
|
87
|
+
/**
|
|
88
|
+
* The layer as the renderer gets it: link layers draw as lines; age fading becomes leading rules on `$age`
|
|
89
|
+
* (rules are per token, so the fade sets opacity — or a dashed outline for areas — and colours fall through).
|
|
90
|
+
*/
|
|
91
|
+
export function effectiveLayer(layer) {
|
|
92
|
+
const vz = layer.visualization;
|
|
93
|
+
let out = layer;
|
|
94
|
+
if (vz.type === 'link')
|
|
95
|
+
out = { ...out, visualization: { ...vz, type: 'line' } };
|
|
96
|
+
if (vz.age && vz.age.fade !== false && vz.type !== 'track') {
|
|
97
|
+
const area = vz.type === 'polygon' || vz.type === 'extrusion' || vz.type === 'image';
|
|
98
|
+
const fade = Object.keys(FADE).map((state) => ({
|
|
99
|
+
property: AGE,
|
|
100
|
+
op: 'eq',
|
|
101
|
+
value: state,
|
|
102
|
+
style: area ? { dash: state === 'ageing' ? [3, 2] : [1.5, 2] } : { opacity: FADE[state] },
|
|
103
|
+
}));
|
|
104
|
+
out = { ...out, visualization: { ...out.visualization, style: [...fade, ...(vz.style ?? [])] } };
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
/** Validates the presentation options of a layer (age, scales, decorations). */
|
|
109
|
+
export function validatePresentation(l) {
|
|
110
|
+
const vz = l.visualization;
|
|
111
|
+
const bad = (reason) => ({ valid: false, reason: `layer ${l.id}: ${reason}` });
|
|
112
|
+
const pos = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0;
|
|
113
|
+
if (vz.age) {
|
|
114
|
+
const a = vz.age;
|
|
115
|
+
if (!pos(a.staleAfterSeconds))
|
|
116
|
+
return bad('age.staleAfterSeconds must be > 0');
|
|
117
|
+
if (a.ageingAfterSeconds !== undefined && !(pos(a.ageingAfterSeconds) && a.ageingAfterSeconds < a.staleAfterSeconds))
|
|
118
|
+
return bad('age.ageingAfterSeconds must be > 0 and below staleAfterSeconds');
|
|
119
|
+
if (a.lostAfterSeconds !== undefined && !(pos(a.lostAfterSeconds) && a.lostAfterSeconds > a.staleAfterSeconds))
|
|
120
|
+
return bad('age.lostAfterSeconds must be above staleAfterSeconds');
|
|
121
|
+
}
|
|
122
|
+
for (const [i, s] of (vz.scales ?? []).entries()) {
|
|
123
|
+
if (typeof s.property !== 'string' || !s.property)
|
|
124
|
+
return bad(`scales[${i}].property is required`);
|
|
125
|
+
if (!['opacity', 'size', 'strokeWidth', 'color', 'strokeColor'].includes(s.token))
|
|
126
|
+
return bad(`scales[${i}].token must be opacity, size, strokeWidth, color or strokeColor`);
|
|
127
|
+
if (!(Array.isArray(s.domain) && s.domain.length === 2 && s.domain.every((n) => typeof n === 'number' && Number.isFinite(n))))
|
|
128
|
+
return bad(`scales[${i}].domain must be [min, max] numbers`);
|
|
129
|
+
const colour = s.token === 'color' || s.token === 'strokeColor';
|
|
130
|
+
const okRange = Array.isArray(s.range) && s.range.length === 2 && (colour ? s.range.every((c) => typeof c === 'string' && HEX.test(c)) : s.range.every((n) => typeof n === 'number' && Number.isFinite(n)));
|
|
131
|
+
if (!okRange)
|
|
132
|
+
return bad(`scales[${i}].range must be ${colour ? 'two #RRGGBB colours' : 'two numbers'}`);
|
|
133
|
+
}
|
|
134
|
+
const pointOnly = (k) => vz[k] && !['marker', 'model', 'volume', 'heatmap'].includes(vz.type);
|
|
135
|
+
for (const k of ['uncertainty', 'rings', 'footprint'])
|
|
136
|
+
if (pointOnly(k))
|
|
137
|
+
return bad(`${k} applies to point layers`);
|
|
138
|
+
if (vz.rings && !(Array.isArray(vz.rings.distancesMeters) && vz.rings.distancesMeters.length > 0 && vz.rings.distancesMeters.every(pos)))
|
|
139
|
+
return bad('rings.distancesMeters must be distances > 0');
|
|
140
|
+
if (vz.footprint && (typeof vz.footprint.headingProperty !== 'string' || !vz.footprint.headingProperty))
|
|
141
|
+
return bad('footprint.headingProperty is required');
|
|
142
|
+
if (vz.link && vz.type !== 'link')
|
|
143
|
+
return bad('link options need visualization.type "link"');
|
|
144
|
+
if (vz.image && vz.type !== 'image')
|
|
145
|
+
return bad('image options need visualization.type "image"');
|
|
146
|
+
if (vz.type === 'image' && !vz.image?.url && !vz.image?.urlProperty)
|
|
147
|
+
return bad('an image layer needs image.url or image.urlProperty');
|
|
148
|
+
return { valid: true };
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { planQueries, type PlannedCall, type QueryPlan } from './planner.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { planQueries } from './planner.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query planner foundation (doc 13). Decides what to push to the provider and what to filter on the client.
|
|
3
|
+
*
|
|
4
|
+
* - Identical layer queries share one provider call (and one realtime subscription).
|
|
5
|
+
* - Spatial predicates and the viewport boundary are pushed down when the provider supports spatial
|
|
6
|
+
* queries; otherwise the call carries only the semantic part and the client filters exactly.
|
|
7
|
+
*/
|
|
8
|
+
import type { BoundingBox, MapLayer, SpatialQuery } from '../core/types.js';
|
|
9
|
+
import type { DataCapabilities } from '../data/contracts.js';
|
|
10
|
+
import { type QueryHints } from '../layers/layers.js';
|
|
11
|
+
export interface PlannedCall {
|
|
12
|
+
key: string;
|
|
13
|
+
/** What the provider is asked. */
|
|
14
|
+
query: SpatialQuery;
|
|
15
|
+
layerIds: string[];
|
|
16
|
+
/** True when spatial parts were left to the client because the provider cannot evaluate them. */
|
|
17
|
+
localSpatial: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface QueryPlan {
|
|
20
|
+
calls: PlannedCall[];
|
|
21
|
+
layers: number;
|
|
22
|
+
/** Layers served by a call another layer already needed. */
|
|
23
|
+
deduplicated: number;
|
|
24
|
+
pushedDown: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function planQueries(layers: MapLayer[], bounds: BoundingBox | undefined, capabilities: DataCapabilities, hints?: QueryHints): QueryPlan;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { layerQuery } from '../layers/layers.js';
|
|
2
|
+
/** Stable key for equal queries regardless of property order. */
|
|
3
|
+
function keyOf(q) {
|
|
4
|
+
const sort = (v) => Array.isArray(v) ? v.map(sort) : v && typeof v === 'object' ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a.localeCompare(b)).map(([k, x]) => [k, sort(x)])) : v;
|
|
5
|
+
return JSON.stringify(sort(q));
|
|
6
|
+
}
|
|
7
|
+
export function planQueries(layers, bounds, capabilities, hints) {
|
|
8
|
+
const calls = new Map();
|
|
9
|
+
const pushedDown = capabilities.supportsSpatialQuery;
|
|
10
|
+
for (const layer of layers) {
|
|
11
|
+
const full = layerQuery(layer, bounds, hints);
|
|
12
|
+
const query = { ...full };
|
|
13
|
+
if (!pushedDown) {
|
|
14
|
+
delete query.spatial;
|
|
15
|
+
delete query.bounds;
|
|
16
|
+
}
|
|
17
|
+
// Layers over one source that draw different geometry types (point / line / area) can share a call;
|
|
18
|
+
// each layer keeps only its own type on the client. A ranking (nearest) must rank drawable objects
|
|
19
|
+
// only, so it keeps its geometry type in the key and in the call.
|
|
20
|
+
const ranked = full.spatial?.relation === 'nearest';
|
|
21
|
+
const shareable = { ...query };
|
|
22
|
+
if (!ranked)
|
|
23
|
+
delete shareable.geometryType;
|
|
24
|
+
const key = keyOf(shareable);
|
|
25
|
+
const existing = calls.get(key);
|
|
26
|
+
if (existing) {
|
|
27
|
+
existing.layerIds.push(layer.id);
|
|
28
|
+
if (full.geometryType)
|
|
29
|
+
existing.geometryTypes.add(full.geometryType);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
calls.set(key, {
|
|
33
|
+
key,
|
|
34
|
+
query: shareable,
|
|
35
|
+
layerIds: [layer.id],
|
|
36
|
+
localSpatial: !pushedDown && (full.spatial !== undefined || full.bounds !== undefined),
|
|
37
|
+
geometryTypes: new Set(full.geometryType ? [full.geometryType] : []),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const list = [...calls.values()].map(({ geometryTypes, ...call }) => {
|
|
42
|
+
// One geometry type for the whole call: let the provider filter it too.
|
|
43
|
+
const only = geometryTypes.size === 1 ? [...geometryTypes][0] : undefined;
|
|
44
|
+
return only && !call.query.geometryType ? { ...call, query: { ...call.query, geometryType: only } } : call;
|
|
45
|
+
});
|
|
46
|
+
return { calls: list, layers: layers.length, deduplicated: layers.length - list.length, pushedDown };
|
|
47
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React integration (doc 19, §48). React owns the container; the engine owns everything spatial.
|
|
3
|
+
* No GIS logic here (Decision: React is the integration layer only).
|
|
4
|
+
*
|
|
5
|
+
* Two ways to use it:
|
|
6
|
+
* - `<MapView config provider createRenderer …>`: MapView creates the runtime (once per provider, realtime,
|
|
7
|
+
* ontology and history) and destroys it on unmount. `config.layers` changes are applied through the runtime API,
|
|
8
|
+
* `config.basemap` changes through setBasemap() — neither remounts.
|
|
9
|
+
* - `<MapView map={runtime}>`: a runtime made outside React (shared, headless-first, or kept across views). MapView
|
|
10
|
+
* only mounts it into its container and unmounts it again; the owner destroys it.
|
|
11
|
+
*
|
|
12
|
+
* `config.viewport` is the initial camera; move the camera with `runtime.setViewport` / `fitBounds` / `flyTo`.
|
|
13
|
+
* `selection` makes selection controlled: the application owns it and pushes it in.
|
|
14
|
+
*/
|
|
15
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
16
|
+
import { MapEngineError } from '../core/errors.js';
|
|
17
|
+
import type { Geofence, GeofenceEvent, MapConfig, MapViewport, Position, SelectionContext, TimeSetting } from '../core/types.js';
|
|
18
|
+
import type { AnnotationProvider, AuthContext, JournalProvider, LinkProvider, OntologySpatialResolver, RealtimeProvider, SpatialDataProvider, TrackProvider } from '../data/contracts.js';
|
|
19
|
+
import type { PickEvent, Renderer } from '../render/renderer.js';
|
|
20
|
+
import { type MapRuntime, type MapRuntimeOptions } from '../runtime/runtime.js';
|
|
21
|
+
/** Props for both forms. With `map={runtime}`, time, geofences and selectable are pushed only when given. */
|
|
22
|
+
export interface MapViewCommonProps {
|
|
23
|
+
/** Application-owned time (ADR-010): live, or replay at a time. Omit for live. */
|
|
24
|
+
time?: TimeSetting;
|
|
25
|
+
/** Geofences evaluated on the client for display (doc 15). Authoritative alerts belong to the server. */
|
|
26
|
+
geofences?: Geofence[];
|
|
27
|
+
/** Live geofence transitions. In replay, read them with `useGeofences()`. */
|
|
28
|
+
onGeofence?: (event: GeofenceEvent) => void;
|
|
29
|
+
/** Controlled selection. Omit for uncontrolled (the map selects on click). */
|
|
30
|
+
selection?: {
|
|
31
|
+
objectIds: string[];
|
|
32
|
+
primaryObjectId?: string;
|
|
33
|
+
source?: string;
|
|
34
|
+
};
|
|
35
|
+
onSelect?: (selection: SelectionContext) => void;
|
|
36
|
+
onViewportChange?: (viewport: MapViewport) => void;
|
|
37
|
+
onMapClick?: (position: Position) => void;
|
|
38
|
+
/** Every click, with what it hit (null on empty map). Use this for tools that need positions over objects. */
|
|
39
|
+
onClick?: (event: {
|
|
40
|
+
position: Position;
|
|
41
|
+
hit: {
|
|
42
|
+
objectId: string;
|
|
43
|
+
layerId: string;
|
|
44
|
+
} | null;
|
|
45
|
+
}) => void;
|
|
46
|
+
/** Click-to-select on/off (default on). Turn off while an app tool uses clicks. */
|
|
47
|
+
selectable?: boolean;
|
|
48
|
+
onHover?: (hover: PickEvent | null) => void;
|
|
49
|
+
onError?: (error: MapEngineError) => void;
|
|
50
|
+
/** Non-fatal problems (a layer without a spatial capability, a mismatched visualization), from the first load on. */
|
|
51
|
+
onWarning?: (warning: MapEngineError) => void;
|
|
52
|
+
/** After the first load. */
|
|
53
|
+
onReady?: (runtime: MapRuntime) => void;
|
|
54
|
+
className?: string;
|
|
55
|
+
style?: CSSProperties;
|
|
56
|
+
/** Overlays (controls, popups). They can use the hooks from this module. */
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
/** MapView creates and owns the runtime. */
|
|
60
|
+
export interface MapViewOwnedProps extends MapViewCommonProps {
|
|
61
|
+
map?: undefined;
|
|
62
|
+
config: MapConfig;
|
|
63
|
+
provider: SpatialDataProvider;
|
|
64
|
+
/** Snapshot + stream: changes arrive without reloading. Often the same object as `provider`. */
|
|
65
|
+
realtime?: RealtimeProvider;
|
|
66
|
+
/** Resolves layer ontology types to spatial bindings; missing capabilities are reported, not guessed. */
|
|
67
|
+
ontology?: OntologySpatialResolver;
|
|
68
|
+
/** Historical positions for track layers and replay. */
|
|
69
|
+
history?: TrackProvider;
|
|
70
|
+
/** Relations between objects, for link layers (doc 28 G4). */
|
|
71
|
+
links?: LinkProvider;
|
|
72
|
+
/** The event journal: replay rebuilds whole objects at a time (doc 29 §7–8). */
|
|
73
|
+
journal?: JournalProvider;
|
|
74
|
+
/** Where annotations are kept and shared (doc 28 G10). */
|
|
75
|
+
annotations?: AnnotationProvider;
|
|
76
|
+
/** Who is looking (doc 28 G13). Changing it hands the new identity to the providers and reloads, in place. */
|
|
77
|
+
auth?: AuthContext | null;
|
|
78
|
+
/** Called once per runtime. Keeps this module renderer-agnostic (e.g. `() => new MapLibreRenderer()`). */
|
|
79
|
+
createRenderer: () => Renderer;
|
|
80
|
+
runtimeOptions?: MapRuntimeOptions;
|
|
81
|
+
}
|
|
82
|
+
/** MapView shows a runtime it does not own (doc §48: `<MapView map={mapRuntime} />`). */
|
|
83
|
+
export interface MapViewRuntimeProps extends MapViewCommonProps {
|
|
84
|
+
map: MapRuntime;
|
|
85
|
+
}
|
|
86
|
+
export type MapViewProps = MapViewOwnedProps | MapViewRuntimeProps;
|
|
87
|
+
export declare function MapView(props: MapViewProps): import("react").JSX.Element;
|