@reearth/core 0.0.7-alpha.23 → 0.0.7-alpha.25
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/dist/core.js +18291 -15855
- package/dist/core.umd.cjs +114 -114
- package/dist/index.d.ts +40 -2
- package/package.json +4 -2
- package/src/Map/Sketch/hooks.ts +28 -2
- package/src/Map/SpatialId/hooks.ts +293 -0
- package/src/Map/SpatialId/index.tsx +36 -0
- package/src/Map/SpatialId/types.ts +45 -0
- package/src/Map/SpatialId/utils.ts +79 -0
- package/src/Map/hooks.ts +21 -2
- package/src/Map/index.tsx +11 -0
- package/src/Map/ref.ts +11 -0
- package/src/Map/types/index.ts +1 -0
- package/src/Visualizer/hooks.ts +1 -0
- package/src/Visualizer/index.tsx +2 -1
- package/src/Visualizer/interactionMode.ts +2 -1
- package/src/engines/Cesium/Feature/Polygon/index.tsx +5 -3
- package/src/engines/Cesium/Feature/Raster/mvt.ts +2 -1
- package/src/engines/Cesium/SpatialId/index.tsx +42 -0
- package/src/engines/Cesium/common.ts +3 -2
- package/src/engines/Cesium/hooks/useEngineRef.ts +3 -2
- package/src/mantle/types/appearance.ts +1 -0
package/dist/index.d.ts
CHANGED
|
@@ -548,7 +548,7 @@ export declare type EngineRef = {
|
|
|
548
548
|
isPositionVisible: (position: [x: number, y: number, z: number]) => boolean;
|
|
549
549
|
setView: (camera: CameraPosition) => void;
|
|
550
550
|
toWindowPosition: (position: [x: number, y: number, z: number]) => [x: number, y: number] | undefined;
|
|
551
|
-
getExtrudedHeight: (position: [x: number, y: number, z: number], windowPosition: [x: number, y: number]) => number | undefined;
|
|
551
|
+
getExtrudedHeight: (position: [x: number, y: number, z: number], windowPosition: [x: number, y: number], allowNegative?: boolean) => number | undefined;
|
|
552
552
|
getExtrudedPoint: (position: [x: number, y: number, z: number], extrutedHeight: number) => Position3d | undefined;
|
|
553
553
|
getSurfaceDistance: (point1: Cartesian3, point2: Cartesian3) => number | undefined;
|
|
554
554
|
equalsEpsilon2d: (point1: Position2d, point2: Position2d, relativeEpsilon: number | undefined, absoluteEpsilon: number | undefined) => boolean;
|
|
@@ -859,7 +859,7 @@ declare type InfoboxProperty = {
|
|
|
859
859
|
|
|
860
860
|
export declare const INTERACTION_MODES: Record<InteractionModeType, number>;
|
|
861
861
|
|
|
862
|
-
export declare type InteractionModeType = "default" | "move" | "selection" | "sketch";
|
|
862
|
+
export declare type InteractionModeType = "default" | "move" | "selection" | "sketch" | "spatialId";
|
|
863
863
|
|
|
864
864
|
export declare function isSketchType(value: unknown): value is SketchType;
|
|
865
865
|
|
|
@@ -1102,6 +1102,7 @@ export declare type MapRef = {
|
|
|
1102
1102
|
engine: WrappedRef<EngineRef>;
|
|
1103
1103
|
layers: WrappedRef<LayersRef>;
|
|
1104
1104
|
sketch: WrappedRef<SketchRef>;
|
|
1105
|
+
spatialId?: WrappedRef<SpatialIdRef>;
|
|
1105
1106
|
timeline?: TimelineManagerRef;
|
|
1106
1107
|
};
|
|
1107
1108
|
|
|
@@ -1291,6 +1292,7 @@ export declare type PolygonAppearance = {
|
|
|
1291
1292
|
stroke?: boolean;
|
|
1292
1293
|
strokeColor?: string;
|
|
1293
1294
|
strokeWidth?: number;
|
|
1295
|
+
height?: number;
|
|
1294
1296
|
heightReference?: "none" | "clamp" | "relative";
|
|
1295
1297
|
shadows?: "disabled" | "enabled" | "cast_only" | "receive_only";
|
|
1296
1298
|
lineJoin?: CanvasLineJoin;
|
|
@@ -1595,6 +1597,42 @@ export declare type Spacing = {
|
|
|
1595
1597
|
top: number;
|
|
1596
1598
|
};
|
|
1597
1599
|
|
|
1600
|
+
declare type SpatialIdPickSpaceOptions = {
|
|
1601
|
+
zoom?: number;
|
|
1602
|
+
maxHeight?: number;
|
|
1603
|
+
color?: string;
|
|
1604
|
+
dataOnly?: boolean;
|
|
1605
|
+
rightClickToExit?: boolean;
|
|
1606
|
+
};
|
|
1607
|
+
|
|
1608
|
+
declare type SpatialIdRef = {
|
|
1609
|
+
pickSpace: (options?: SpatialIdPickSpaceOptions) => void;
|
|
1610
|
+
exitPickSpace: () => void;
|
|
1611
|
+
onSpacePick: (cb: (space: SpatialIdSpaceData) => void) => void;
|
|
1612
|
+
};
|
|
1613
|
+
|
|
1614
|
+
declare type SpatialIdSpaceData = {
|
|
1615
|
+
id: string;
|
|
1616
|
+
center: {
|
|
1617
|
+
lat: number;
|
|
1618
|
+
lng: number;
|
|
1619
|
+
alt?: number;
|
|
1620
|
+
};
|
|
1621
|
+
alt: number;
|
|
1622
|
+
zoom: number;
|
|
1623
|
+
zfxy: {
|
|
1624
|
+
z: number;
|
|
1625
|
+
f: number;
|
|
1626
|
+
x: number;
|
|
1627
|
+
y: number;
|
|
1628
|
+
};
|
|
1629
|
+
zfxyStr: string;
|
|
1630
|
+
tilehash: string;
|
|
1631
|
+
hilbertTilehash: string;
|
|
1632
|
+
hilbertIndex: string;
|
|
1633
|
+
vertices: [number, number, number][];
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1598
1636
|
export declare type StyleExpression = ConditionsExpression | string;
|
|
1599
1637
|
|
|
1600
1638
|
export declare type SunProperty = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reearth/core",
|
|
3
|
-
"version": "0.0.7-alpha.
|
|
3
|
+
"version": "0.0.7-alpha.25",
|
|
4
4
|
"author": "Re:Earth contributors <community@reearth.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "A library that abstracts a map engine as one common API.",
|
|
@@ -38,12 +38,14 @@
|
|
|
38
38
|
"@radix-ui/react-icons": "1.3.0",
|
|
39
39
|
"@radix-ui/react-select": "2.1.1",
|
|
40
40
|
"@radix-ui/react-separator": "1.1.0",
|
|
41
|
+
"@radix-ui/react-slider": "1.2.2",
|
|
41
42
|
"@radix-ui/react-slot": "1.1.0",
|
|
42
43
|
"@radix-ui/react-switch": "1.1.0",
|
|
43
44
|
"@radix-ui/react-toggle": "1.1.0",
|
|
44
|
-
"@reearth/cesium-mvt-imagery-provider": "1.
|
|
45
|
+
"@reearth/cesium-mvt-imagery-provider": "1.6.0",
|
|
45
46
|
"@rot1024/use-transition": "1.0.0",
|
|
46
47
|
"@seznam/compose-react-refs": "1.0.6",
|
|
48
|
+
"@spatial-id/javascript-sdk": "https://github.com/spatial-id/javascript-sdk",
|
|
47
49
|
"@turf/invariant": "6.5.0",
|
|
48
50
|
"@turf/turf": "6.5.0",
|
|
49
51
|
"@types/proj4": "2.5.5",
|
package/src/Map/Sketch/hooks.ts
CHANGED
|
@@ -71,6 +71,7 @@ export default function ({
|
|
|
71
71
|
ref,
|
|
72
72
|
engineRef,
|
|
73
73
|
layersRef,
|
|
74
|
+
interactionMode,
|
|
74
75
|
selectedFeature,
|
|
75
76
|
overrideInteractionMode,
|
|
76
77
|
onSketchTypeChange,
|
|
@@ -333,6 +334,7 @@ export default function ({
|
|
|
333
334
|
useWindowEvent("keydown", event => {
|
|
334
335
|
if (type === undefined) return;
|
|
335
336
|
if (event.code === "Space") {
|
|
337
|
+
tempSwitchToMoveMode.current = true;
|
|
336
338
|
setDisableInteraction(true);
|
|
337
339
|
overrideInteractionMode?.("move");
|
|
338
340
|
} else {
|
|
@@ -360,6 +362,9 @@ export default function ({
|
|
|
360
362
|
if (event.code === "Space") {
|
|
361
363
|
overrideInteractionMode?.("sketch");
|
|
362
364
|
setDisableInteraction(false);
|
|
365
|
+
if (tempSwitchToMoveMode.current) {
|
|
366
|
+
tempSwitchToMoveMode.current = false;
|
|
367
|
+
}
|
|
363
368
|
}
|
|
364
369
|
});
|
|
365
370
|
|
|
@@ -376,9 +381,17 @@ export default function ({
|
|
|
376
381
|
overrideInteractionModeRef.current = overrideInteractionMode;
|
|
377
382
|
const onSketchTypeChangeRef = useRef(onSketchTypeChange);
|
|
378
383
|
onSketchTypeChangeRef.current = onSketchTypeChange;
|
|
384
|
+
const interactionModeRef = useRef(interactionMode);
|
|
385
|
+
interactionModeRef.current = interactionMode;
|
|
379
386
|
|
|
380
387
|
useEffect(() => {
|
|
381
|
-
overrideInteractionModeRef.current?.(
|
|
388
|
+
overrideInteractionModeRef.current?.(
|
|
389
|
+
type || sketchEditingFeature
|
|
390
|
+
? "sketch"
|
|
391
|
+
: interactionModeRef.current === "sketch"
|
|
392
|
+
? "default"
|
|
393
|
+
: interactionModeRef.current,
|
|
394
|
+
);
|
|
382
395
|
}, [type, sketchEditingFeature]);
|
|
383
396
|
|
|
384
397
|
const isEditingRef = useRef(isEditing);
|
|
@@ -393,6 +406,19 @@ export default function ({
|
|
|
393
406
|
}
|
|
394
407
|
}, [type]);
|
|
395
408
|
|
|
409
|
+
const typeRef = useRef(type);
|
|
410
|
+
typeRef.current = type;
|
|
411
|
+
useEffect(() => {
|
|
412
|
+
if (tempSwitchToMoveMode.current) return;
|
|
413
|
+
if (interactionMode !== "sketch") {
|
|
414
|
+
if (isEditingRef.current) {
|
|
415
|
+
cancelEditRef.current();
|
|
416
|
+
} else if (typeRef.current !== undefined) {
|
|
417
|
+
updateType(undefined);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}, [interactionMode, updateType]);
|
|
421
|
+
|
|
396
422
|
// Edit
|
|
397
423
|
const onEditFeatureChangeCbs = useRef<SketchEditFeatureChangeCb[]>([]);
|
|
398
424
|
const onEditFeatureChange = useCallback((cb: SketchEditFeatureChangeCb) => {
|
|
@@ -569,8 +595,8 @@ export default function ({
|
|
|
569
595
|
useEffect(() => {
|
|
570
596
|
return window.addEventListener("keydown", event => {
|
|
571
597
|
if (event.code === "Space" && stateRef.current.matches("editing")) {
|
|
572
|
-
overrideInteractionMode?.("move");
|
|
573
598
|
tempSwitchToMoveMode.current = true;
|
|
599
|
+
overrideInteractionMode?.("move");
|
|
574
600
|
} else if (event.code === "Delete" && stateRef.current.matches("editing")) {
|
|
575
601
|
handleDeleteControlPointRef.current();
|
|
576
602
|
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ForwardedRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { RefObject } from "use-callback-ref/dist/es5/types";
|
|
11
|
+
|
|
12
|
+
import { InteractionModeType } from "../../Visualizer";
|
|
13
|
+
import { EngineRef, MouseEventProps } from "../types";
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
SpatialIdRef,
|
|
17
|
+
SpatialIdSpacePickingState,
|
|
18
|
+
SpatialIdSpaceType,
|
|
19
|
+
SpatialIdSpaceData,
|
|
20
|
+
SpatialIdPickSpaceOptions,
|
|
21
|
+
} from "./types";
|
|
22
|
+
import { createSpatialIdFloorSpaces, createSpatialIdSpace, getSpaceData } from "./utils";
|
|
23
|
+
|
|
24
|
+
type Props = {
|
|
25
|
+
ref: ForwardedRef<SpatialIdRef>;
|
|
26
|
+
engineRef: RefObject<EngineRef>;
|
|
27
|
+
terrainEnabled?: boolean;
|
|
28
|
+
interactionMode?: InteractionModeType;
|
|
29
|
+
overrideInteractionMode?: (mode: InteractionModeType) => void;
|
|
30
|
+
onMount?: () => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const SPATIALID_DEFAULT_ZOOM = 20;
|
|
34
|
+
export const SPATIALID_DEFAULT_MAX_HEIGHT = 1000;
|
|
35
|
+
export const SPATIALID_DEFAULT_COLOR = "#00bebe";
|
|
36
|
+
export const SPATIALID_DEFAULT_DATA_ONLY = false;
|
|
37
|
+
export const SPATIALID_DEFAULT_RIGHT_CLICK_TO_EXIT = true;
|
|
38
|
+
|
|
39
|
+
export default ({
|
|
40
|
+
ref,
|
|
41
|
+
engineRef,
|
|
42
|
+
terrainEnabled,
|
|
43
|
+
interactionMode,
|
|
44
|
+
overrideInteractionMode,
|
|
45
|
+
onMount,
|
|
46
|
+
}: Props) => {
|
|
47
|
+
const [state, setState] = useState<SpatialIdSpacePickingState>("idle");
|
|
48
|
+
|
|
49
|
+
const [spatialIdSpaces, setSpatialIdSpaces] = useState<SpatialIdSpaceType[]>([]);
|
|
50
|
+
const [floorSpaces, setFloorSpaces] = useState<SpatialIdSpaceType[]>([]);
|
|
51
|
+
const [selectorSpace, setSelectorSpace] = useState<SpatialIdSpaceType | null>(null);
|
|
52
|
+
|
|
53
|
+
const spaces = useMemo(() => {
|
|
54
|
+
return [...spatialIdSpaces, ...floorSpaces, ...(selectorSpace ? [selectorSpace] : [])];
|
|
55
|
+
}, [spatialIdSpaces, floorSpaces, selectorSpace]);
|
|
56
|
+
|
|
57
|
+
const [basePosition, setBasePosition] = useState<[number, number, number] | null>(null);
|
|
58
|
+
const [baseCoordinate, setBaseCoordinate] = useState<[number, number, number] | null>(null);
|
|
59
|
+
|
|
60
|
+
const [pickOptions, setPickOptions] = useState<Required<SpatialIdPickSpaceOptions>>({
|
|
61
|
+
zoom: SPATIALID_DEFAULT_ZOOM,
|
|
62
|
+
maxHeight: SPATIALID_DEFAULT_MAX_HEIGHT,
|
|
63
|
+
color: SPATIALID_DEFAULT_COLOR,
|
|
64
|
+
dataOnly: SPATIALID_DEFAULT_DATA_ONLY,
|
|
65
|
+
rightClickToExit: SPATIALID_DEFAULT_RIGHT_CLICK_TO_EXIT,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const pickSpace = useCallback(
|
|
69
|
+
(options?: SpatialIdPickSpaceOptions) => {
|
|
70
|
+
setState("coordinate");
|
|
71
|
+
setPickOptions(prev => ({ ...prev, ...options }));
|
|
72
|
+
overrideInteractionMode?.("spatialId");
|
|
73
|
+
},
|
|
74
|
+
[overrideInteractionMode],
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const interactionModeRef = useRef(interactionMode);
|
|
78
|
+
interactionModeRef.current = interactionMode;
|
|
79
|
+
|
|
80
|
+
const finishPicking = useCallback(() => {
|
|
81
|
+
setState("idle");
|
|
82
|
+
setSelectorSpace(null);
|
|
83
|
+
setBasePosition(null);
|
|
84
|
+
setBaseCoordinate(null);
|
|
85
|
+
setFloorSpaces([]);
|
|
86
|
+
overrideInteractionMode?.(
|
|
87
|
+
interactionModeRef.current === "spatialId"
|
|
88
|
+
? "default"
|
|
89
|
+
: interactionModeRef.current ?? "default",
|
|
90
|
+
);
|
|
91
|
+
engineRef.current?.requestRender();
|
|
92
|
+
}, [overrideInteractionMode, engineRef]);
|
|
93
|
+
|
|
94
|
+
// handle events
|
|
95
|
+
const handleMouseUp = useCallback(
|
|
96
|
+
(props: MouseEventProps) => {
|
|
97
|
+
if (state === "idle") return;
|
|
98
|
+
if (tempSwitchToMoveMode.current) return;
|
|
99
|
+
|
|
100
|
+
if (state === "coordinate") {
|
|
101
|
+
if (!selectorSpace || props.lat === undefined || props.lng === undefined) return;
|
|
102
|
+
setState("floor");
|
|
103
|
+
setBaseCoordinate([props.lng, props.lat, terrainEnabled ? props.height ?? 0 : 0]);
|
|
104
|
+
setBasePosition(
|
|
105
|
+
engineRef.current?.toXYZ(props.lng, props.lat, props.height ?? 0, {
|
|
106
|
+
useGlobeEllipsoid: !terrainEnabled,
|
|
107
|
+
}) ?? null,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
setSelectorSpace(prev =>
|
|
111
|
+
prev ? { ...prev, type: "selector", color: pickOptions.color } : null,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const floorSpaces = createSpatialIdFloorSpaces(
|
|
115
|
+
selectorSpace.space,
|
|
116
|
+
pickOptions.maxHeight,
|
|
117
|
+
pickOptions.color,
|
|
118
|
+
);
|
|
119
|
+
setFloorSpaces(floorSpaces);
|
|
120
|
+
} else if (state === "floor") {
|
|
121
|
+
if (!selectorSpace) return;
|
|
122
|
+
|
|
123
|
+
const confirmedSpace: SpatialIdSpaceType = {
|
|
124
|
+
...selectorSpace,
|
|
125
|
+
type: "confirmed",
|
|
126
|
+
color: pickOptions.color,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
if (!pickOptions.dataOnly) {
|
|
130
|
+
setSpatialIdSpaces(prev => [...prev, confirmedSpace]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
finishPicking();
|
|
134
|
+
|
|
135
|
+
const spaceData = getSpaceData(confirmedSpace.space);
|
|
136
|
+
onSpacePickEvents.current.forEach(cb => cb(spaceData));
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
[state, terrainEnabled, engineRef, selectorSpace, pickOptions, finishPicking],
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
const handleMouseMove = useCallback(
|
|
143
|
+
(props: MouseEventProps) => {
|
|
144
|
+
if (state === "idle") return;
|
|
145
|
+
if (tempSwitchToMoveMode.current) return;
|
|
146
|
+
|
|
147
|
+
if (state === "coordinate") {
|
|
148
|
+
if (props.lat === undefined || props.lng === undefined) return;
|
|
149
|
+
|
|
150
|
+
const newSpace = createSpatialIdSpace(
|
|
151
|
+
props.lng,
|
|
152
|
+
props.lat,
|
|
153
|
+
terrainEnabled ? props.height ?? 0 : 0,
|
|
154
|
+
pickOptions.zoom,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (newSpace.space.id === selectorSpace?.space.id) return;
|
|
158
|
+
|
|
159
|
+
setSelectorSpace({ ...newSpace, type: "coordinate", color: pickOptions.color });
|
|
160
|
+
} else if (state === "floor") {
|
|
161
|
+
if (
|
|
162
|
+
props.x === undefined ||
|
|
163
|
+
props.y === undefined ||
|
|
164
|
+
basePosition === null ||
|
|
165
|
+
baseCoordinate === null
|
|
166
|
+
)
|
|
167
|
+
return;
|
|
168
|
+
|
|
169
|
+
const height =
|
|
170
|
+
engineRef.current?.getExtrudedHeight(basePosition, [props.x, props.y], true) ?? 0;
|
|
171
|
+
|
|
172
|
+
if (baseCoordinate[2] + height > pickOptions.maxHeight) return;
|
|
173
|
+
|
|
174
|
+
const newSpace = createSpatialIdSpace(
|
|
175
|
+
baseCoordinate[0],
|
|
176
|
+
baseCoordinate[1],
|
|
177
|
+
baseCoordinate[2] + height,
|
|
178
|
+
pickOptions.zoom,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
if (newSpace.space.id === selectorSpace?.space.id || newSpace.space.zfxy.f < 0) return;
|
|
182
|
+
|
|
183
|
+
setSelectorSpace({ ...newSpace, type: "selector", color: pickOptions.color });
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
[state, selectorSpace, basePosition, baseCoordinate, engineRef, terrainEnabled, pickOptions],
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const handleMouseRightClick = useCallback(() => {
|
|
190
|
+
if (state === "idle") return;
|
|
191
|
+
if (state === "coordinate" && pickOptions.rightClickToExit) {
|
|
192
|
+
finishPicking();
|
|
193
|
+
} else if (state === "floor") {
|
|
194
|
+
setSelectorSpace(null);
|
|
195
|
+
setBasePosition(null);
|
|
196
|
+
setBaseCoordinate(null);
|
|
197
|
+
setFloorSpaces([]);
|
|
198
|
+
setState("coordinate");
|
|
199
|
+
}
|
|
200
|
+
engineRef.current?.requestRender();
|
|
201
|
+
}, [state, pickOptions, engineRef, finishPicking]);
|
|
202
|
+
|
|
203
|
+
// bind mouse events
|
|
204
|
+
const eventsBinded = useRef(false);
|
|
205
|
+
|
|
206
|
+
const handleMouseUpRef = useRef(handleMouseUp);
|
|
207
|
+
handleMouseUpRef.current = handleMouseUp;
|
|
208
|
+
const handleMouseUpForRef = useCallback((props: MouseEventProps) => {
|
|
209
|
+
handleMouseUpRef.current(props);
|
|
210
|
+
}, []);
|
|
211
|
+
|
|
212
|
+
const handleMouseMoveRef = useRef(handleMouseMove);
|
|
213
|
+
handleMouseMoveRef.current = handleMouseMove;
|
|
214
|
+
const handleMouseMoveForRef = useCallback((props: MouseEventProps) => {
|
|
215
|
+
handleMouseMoveRef.current(props);
|
|
216
|
+
}, []);
|
|
217
|
+
|
|
218
|
+
const handleMouseRightClickRef = useRef(handleMouseRightClick);
|
|
219
|
+
handleMouseRightClickRef.current = handleMouseRightClick;
|
|
220
|
+
const handleMouseRightClickForRef = useCallback(() => {
|
|
221
|
+
handleMouseRightClickRef.current();
|
|
222
|
+
}, []);
|
|
223
|
+
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
if (eventsBinded.current || !engineRef.current) return;
|
|
226
|
+
eventsBinded.current = true;
|
|
227
|
+
engineRef.current.onMouseUp(handleMouseUpForRef);
|
|
228
|
+
engineRef.current.onMouseMove(handleMouseMoveForRef);
|
|
229
|
+
engineRef.current.onRightClick(handleMouseRightClickForRef);
|
|
230
|
+
}, [engineRef, handleMouseUpForRef, handleMouseMoveForRef, handleMouseRightClickForRef]);
|
|
231
|
+
|
|
232
|
+
// cancel picking when interaction mode changes
|
|
233
|
+
const stateRef = useRef(state);
|
|
234
|
+
stateRef.current = state;
|
|
235
|
+
const finishPickingRef = useRef(finishPicking);
|
|
236
|
+
finishPickingRef.current = finishPicking;
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
if (tempSwitchToMoveMode.current) return;
|
|
239
|
+
if (interactionMode !== "spatialId" && stateRef.current !== "idle") {
|
|
240
|
+
finishPickingRef.current();
|
|
241
|
+
}
|
|
242
|
+
}, [interactionMode]);
|
|
243
|
+
|
|
244
|
+
// events
|
|
245
|
+
const onSpacePickEvents = useRef<((space: SpatialIdSpaceData) => void)[]>([]);
|
|
246
|
+
|
|
247
|
+
const bindEventOnSpacePick = useCallback((cb: (space: SpatialIdSpaceData) => void) => {
|
|
248
|
+
onSpacePickEvents.current.push(cb);
|
|
249
|
+
}, []);
|
|
250
|
+
|
|
251
|
+
// ref
|
|
252
|
+
useImperativeHandle(
|
|
253
|
+
ref,
|
|
254
|
+
() => ({
|
|
255
|
+
pickSpace,
|
|
256
|
+
onSpacePick: bindEventOnSpacePick,
|
|
257
|
+
exitPickSpace: finishPicking,
|
|
258
|
+
}),
|
|
259
|
+
[pickSpace, bindEventOnSpacePick, finishPicking],
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// press space to move
|
|
263
|
+
const tempSwitchToMoveMode = useRef(false);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
const handleKeydown = (e: KeyboardEvent) => {
|
|
266
|
+
if (e.code === "Space" && stateRef.current !== "idle") {
|
|
267
|
+
tempSwitchToMoveMode.current = true;
|
|
268
|
+
overrideInteractionMode?.("move");
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
window.addEventListener("keydown", handleKeydown);
|
|
272
|
+
return () => {
|
|
273
|
+
window.removeEventListener("keydown", handleKeydown);
|
|
274
|
+
};
|
|
275
|
+
}, [overrideInteractionMode]);
|
|
276
|
+
|
|
277
|
+
useEffect(() => {
|
|
278
|
+
return window.addEventListener("keyup", e => {
|
|
279
|
+
if (e.code === "Space" && tempSwitchToMoveMode.current) {
|
|
280
|
+
tempSwitchToMoveMode.current = false;
|
|
281
|
+
overrideInteractionMode?.("spatialId");
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}, [overrideInteractionMode]);
|
|
285
|
+
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
onMount?.();
|
|
288
|
+
}, [onMount]);
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
spaces,
|
|
292
|
+
};
|
|
293
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { forwardRef, ForwardRefRenderFunction } from "react";
|
|
2
|
+
import { RefObject } from "use-callback-ref/dist/es5/types";
|
|
3
|
+
|
|
4
|
+
import SpatialIdSpace from "../../engines/Cesium/SpatialId";
|
|
5
|
+
import { InteractionModeType } from "../../Visualizer";
|
|
6
|
+
import { EngineRef } from "../types";
|
|
7
|
+
|
|
8
|
+
import useHooks from "./hooks";
|
|
9
|
+
import { SpatialIdRef } from "./types";
|
|
10
|
+
|
|
11
|
+
type SpatialIdProps = {
|
|
12
|
+
engineRef: RefObject<EngineRef>;
|
|
13
|
+
terrainEnabled?: boolean;
|
|
14
|
+
interactionMode?: InteractionModeType;
|
|
15
|
+
overrideInteractionMode?: (mode: InteractionModeType) => void;
|
|
16
|
+
onMount?: () => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const SpatialId: ForwardRefRenderFunction<SpatialIdRef, SpatialIdProps> = (
|
|
20
|
+
{ engineRef, terrainEnabled, interactionMode, overrideInteractionMode, onMount },
|
|
21
|
+
ref,
|
|
22
|
+
) => {
|
|
23
|
+
const { spaces } = useHooks({
|
|
24
|
+
ref,
|
|
25
|
+
engineRef,
|
|
26
|
+
terrainEnabled,
|
|
27
|
+
interactionMode,
|
|
28
|
+
overrideInteractionMode,
|
|
29
|
+
onMount,
|
|
30
|
+
});
|
|
31
|
+
return spaces.length > 0
|
|
32
|
+
? spaces.map(space => <SpatialIdSpace key={space.id} space={space} />)
|
|
33
|
+
: null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default forwardRef(SpatialId);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Space } from "@spatial-id/javascript-sdk";
|
|
2
|
+
|
|
3
|
+
export type SpatialIdSpaceType = {
|
|
4
|
+
id: string;
|
|
5
|
+
space: Space;
|
|
6
|
+
wsen: [number, number, number, number];
|
|
7
|
+
height: number;
|
|
8
|
+
extrudedHeight: number;
|
|
9
|
+
type?: "selector" | "floor" | "coordinate" | "confirmed";
|
|
10
|
+
color?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SpatialIdPickSpaceOptions = {
|
|
14
|
+
zoom?: number;
|
|
15
|
+
maxHeight?: number;
|
|
16
|
+
color?: string;
|
|
17
|
+
dataOnly?: boolean;
|
|
18
|
+
rightClickToExit?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type SpatialIdRef = {
|
|
22
|
+
pickSpace: (options?: SpatialIdPickSpaceOptions) => void;
|
|
23
|
+
exitPickSpace: () => void;
|
|
24
|
+
onSpacePick: (cb: (space: SpatialIdSpaceData) => void) => void;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type SpatialIdSpacePickingState = "idle" | "coordinate" | "floor";
|
|
28
|
+
|
|
29
|
+
export type SpatialIdSpaceData = {
|
|
30
|
+
id: string;
|
|
31
|
+
center: { lat: number; lng: number; alt?: number };
|
|
32
|
+
alt: number;
|
|
33
|
+
zoom: number;
|
|
34
|
+
zfxy: {
|
|
35
|
+
z: number;
|
|
36
|
+
f: number;
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
zfxyStr: string;
|
|
41
|
+
tilehash: string;
|
|
42
|
+
hilbertTilehash: string;
|
|
43
|
+
hilbertIndex: string;
|
|
44
|
+
vertices: [number, number, number][];
|
|
45
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Space } from "@spatial-id/javascript-sdk";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { SPATIALID_DEFAULT_COLOR, SPATIALID_DEFAULT_MAX_HEIGHT } from "./hooks";
|
|
5
|
+
import { SpatialIdSpaceType, SpatialIdSpaceData } from "./types";
|
|
6
|
+
|
|
7
|
+
const getRectangeParamsFromSpace = (space: Space) => {
|
|
8
|
+
const vertices = space.vertices3d();
|
|
9
|
+
const wsen: [number, number, number, number] = [
|
|
10
|
+
vertices[0][0],
|
|
11
|
+
vertices[1][1],
|
|
12
|
+
vertices[2][0],
|
|
13
|
+
vertices[3][1],
|
|
14
|
+
];
|
|
15
|
+
const height = vertices[0][2];
|
|
16
|
+
const extrudedHeight = vertices[4][2];
|
|
17
|
+
return { wsen, height, extrudedHeight };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const createSpatialIdSpace = (
|
|
21
|
+
lng: number,
|
|
22
|
+
lat: number,
|
|
23
|
+
alt: number,
|
|
24
|
+
zoom: number,
|
|
25
|
+
): SpatialIdSpaceType => {
|
|
26
|
+
const space = new Space({ lat, lng, alt }, zoom);
|
|
27
|
+
const { wsen, height, extrudedHeight } = getRectangeParamsFromSpace(space);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
id: uuid(),
|
|
31
|
+
space,
|
|
32
|
+
wsen,
|
|
33
|
+
height,
|
|
34
|
+
extrudedHeight,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const createSpatialIdFloorSpaces = (
|
|
39
|
+
space: Space,
|
|
40
|
+
maxHeight = SPATIALID_DEFAULT_MAX_HEIGHT,
|
|
41
|
+
color = SPATIALID_DEFAULT_COLOR,
|
|
42
|
+
) => {
|
|
43
|
+
const floorSpaces: SpatialIdSpaceType[] = [];
|
|
44
|
+
const { height, extrudedHeight } = getRectangeParamsFromSpace(space);
|
|
45
|
+
const heightStep = extrudedHeight - height;
|
|
46
|
+
for (let h = 0; h < maxHeight; h += heightStep) {
|
|
47
|
+
const fSpace = new Space({ lat: space.center.lat, lng: space.center.lng, alt: h }, space.zoom);
|
|
48
|
+
const {
|
|
49
|
+
wsen: fWsen,
|
|
50
|
+
height: fHeight,
|
|
51
|
+
extrudedHeight: fExtrudedHeight,
|
|
52
|
+
} = getRectangeParamsFromSpace(fSpace);
|
|
53
|
+
floorSpaces.push({
|
|
54
|
+
id: uuid(),
|
|
55
|
+
space: fSpace,
|
|
56
|
+
wsen: fWsen,
|
|
57
|
+
height: fHeight,
|
|
58
|
+
extrudedHeight: fExtrudedHeight,
|
|
59
|
+
type: "floor",
|
|
60
|
+
color,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return floorSpaces;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const getSpaceData = (space: Space): SpatialIdSpaceData => {
|
|
67
|
+
return {
|
|
68
|
+
id: space.id,
|
|
69
|
+
center: space.center,
|
|
70
|
+
alt: space.alt,
|
|
71
|
+
zoom: space.zoom,
|
|
72
|
+
zfxy: space.zfxy,
|
|
73
|
+
zfxyStr: space.zfxyStr,
|
|
74
|
+
tilehash: space.tilehash,
|
|
75
|
+
hilbertTilehash: space.hilbertTilehash,
|
|
76
|
+
hilbertIndex: space.hilbertIndex.toString(),
|
|
77
|
+
vertices: space.vertices3d(),
|
|
78
|
+
};
|
|
79
|
+
};
|
package/src/Map/hooks.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { useImperativeHandle, useRef, type Ref, useState, useCallback, useEffect
|
|
|
3
3
|
import { SelectedFeatureInfo } from "../mantle";
|
|
4
4
|
|
|
5
5
|
import { type MapRef, mapRef } from "./ref";
|
|
6
|
+
import { SpatialIdRef } from "./SpatialId/types";
|
|
6
7
|
import type {
|
|
7
8
|
EngineRef,
|
|
8
9
|
LayersRef,
|
|
@@ -42,10 +43,16 @@ export default function ({
|
|
|
42
43
|
onMount?: () => void;
|
|
43
44
|
onAPIReady?: () => void;
|
|
44
45
|
}) {
|
|
45
|
-
const [mapAPIReady, setMapAPIReady] = useState({
|
|
46
|
+
const [mapAPIReady, setMapAPIReady] = useState({
|
|
47
|
+
engine: false,
|
|
48
|
+
layers: false,
|
|
49
|
+
sketch: false,
|
|
50
|
+
spatialId: false,
|
|
51
|
+
});
|
|
46
52
|
const engineRef = useRef<EngineRef>(null);
|
|
47
53
|
const layersRef = useRef<LayersRef>(null);
|
|
48
54
|
const sketchRef = useRef<SketchRef>(null);
|
|
55
|
+
const spatialIdRef = useRef<SpatialIdRef>(null);
|
|
49
56
|
const requestingRenderMode = useRef<RequestingRenderMode>(NO_REQUEST_RENDER);
|
|
50
57
|
|
|
51
58
|
useImperativeHandle(
|
|
@@ -55,13 +62,20 @@ export default function ({
|
|
|
55
62
|
engineRef,
|
|
56
63
|
layersRef,
|
|
57
64
|
sketchRef,
|
|
65
|
+
spatialIdRef,
|
|
58
66
|
timelineManagerRef,
|
|
59
67
|
}),
|
|
60
68
|
[timelineManagerRef],
|
|
61
69
|
);
|
|
62
70
|
|
|
63
71
|
useEffect(() => {
|
|
64
|
-
if (
|
|
72
|
+
if (
|
|
73
|
+
onAPIReady &&
|
|
74
|
+
mapAPIReady.engine &&
|
|
75
|
+
mapAPIReady.layers &&
|
|
76
|
+
mapAPIReady.sketch &&
|
|
77
|
+
mapAPIReady.spatialId
|
|
78
|
+
) {
|
|
65
79
|
onAPIReady?.();
|
|
66
80
|
}
|
|
67
81
|
}, [onAPIReady, mapAPIReady]);
|
|
@@ -136,11 +150,15 @@ export default function ({
|
|
|
136
150
|
const handleSketchMount = useCallback(() => {
|
|
137
151
|
setMapAPIReady(s => ({ ...s, sketch: true }));
|
|
138
152
|
}, []);
|
|
153
|
+
const handleSpatialIdMount = useCallback(() => {
|
|
154
|
+
setMapAPIReady(s => ({ ...s, spatialId: true }));
|
|
155
|
+
}, []);
|
|
139
156
|
|
|
140
157
|
return {
|
|
141
158
|
engineRef,
|
|
142
159
|
layersRef,
|
|
143
160
|
sketchRef,
|
|
161
|
+
spatialIdRef,
|
|
144
162
|
selectedLayer,
|
|
145
163
|
requestingRenderMode,
|
|
146
164
|
handleLayerSelect,
|
|
@@ -150,5 +168,6 @@ export default function ({
|
|
|
150
168
|
handleEngineMount,
|
|
151
169
|
handleLayersMount,
|
|
152
170
|
handleSketchMount,
|
|
171
|
+
handleSpatialIdMount,
|
|
153
172
|
};
|
|
154
173
|
}
|