@reearth/core 0.0.7-alpha.14 → 0.0.7-alpha.16

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.
Files changed (40) hide show
  1. package/dist/core.js +7164 -5873
  2. package/dist/core.umd.cjs +71 -71
  3. package/dist/index.d.ts +62 -13
  4. package/package.json +8 -5
  5. package/src/Map/Layer/hooks.ts +6 -3
  6. package/src/Map/Layer/index.tsx +2 -0
  7. package/src/Map/Layers/hooks.ts +17 -0
  8. package/src/Map/Layers/index.tsx +12 -1
  9. package/src/Map/Layers/keys.ts +1 -0
  10. package/src/Map/Sketch/hooks.ts +405 -399
  11. package/src/Map/Sketch/index.tsx +65 -18
  12. package/src/Map/Sketch/sketchMachine.ts +359 -4
  13. package/src/Map/Sketch/sketchMachine.typegen.ts +58 -1
  14. package/src/Map/Sketch/types.ts +10 -20
  15. package/src/Map/Sketch/usePluginSketchLayer.ts +105 -0
  16. package/src/Map/Sketch/useSketch.ts +559 -0
  17. package/src/Map/Sketch/useSketchFeature.ts +198 -0
  18. package/src/Map/hooks.ts +32 -1
  19. package/src/Map/index.tsx +24 -0
  20. package/src/Map/ref.ts +8 -0
  21. package/src/Map/types/index.ts +27 -1
  22. package/src/Visualizer/coreContext.tsx +2 -0
  23. package/src/Visualizer/hooks.ts +25 -0
  24. package/src/Visualizer/index.tsx +20 -0
  25. package/src/engines/Cesium/Feature/index.tsx +6 -2
  26. package/src/engines/Cesium/Sketch/ControlPoint.tsx +128 -24
  27. package/src/engines/Cesium/Sketch/ExtrudedControlPoints.tsx +70 -25
  28. package/src/engines/Cesium/Sketch/ExtrudedMeasurement.tsx +3 -1
  29. package/src/engines/Cesium/Sketch/ExtrudedPolygonEntity.tsx +14 -14
  30. package/src/engines/Cesium/Sketch/PolylineEntity.tsx +7 -4
  31. package/src/engines/Cesium/Sketch/SurfaceAddingPoints.tsx +60 -0
  32. package/src/engines/Cesium/Sketch/SurfaceControlPoints.tsx +125 -35
  33. package/src/engines/Cesium/Sketch/constants.ts +5 -0
  34. package/src/engines/Cesium/Sketch/index.tsx +68 -29
  35. package/src/engines/Cesium/core/Globe.tsx +11 -2
  36. package/src/engines/Cesium/core/Imagery.tsx +7 -2
  37. package/src/engines/Cesium/core/presets.ts +0 -11
  38. package/src/engines/Cesium/hooks/useEngineRef.ts +36 -0
  39. package/src/engines/Cesium/hooks.ts +50 -0
  40. package/src/engines/Cesium/index.tsx +16 -3
@@ -1,62 +1,152 @@
1
- import { Cartesian3, type Color } from "@cesium/engine";
1
+ import { Cartesian3, Color } from "@cesium/engine";
2
2
  import { memo, type FC } from "react";
3
3
 
4
+ import { DEFAULT_EDIT_COLOR } from "./constants";
4
5
  import { ControlPoint } from "./ControlPoint";
5
6
  import { type GeometryOptions } from "./createGeometry";
6
7
  import { SurfaceMeasurement } from "./SurfaceMeasurement";
7
8
 
9
+ import { ControlPointMouseEventHandler } from ".";
10
+
8
11
  export interface SurfaceControlPointsProps {
9
12
  geometryOptions: GeometryOptions;
10
13
  color?: Color;
14
+ isEditing?: boolean;
15
+ selectedControlPointIndex?: number;
16
+ catchedControlPointIndex?: number;
17
+ handleControlPointMouseEvent?: ControlPointMouseEventHandler;
11
18
  }
12
19
 
13
20
  const cartesianScratch1 = new Cartesian3();
14
- const cartesianScratch2 = new Cartesian3();
15
21
 
16
22
  const SurfaceControlPoints: FC<SurfaceControlPointsProps> = memo(
17
- ({ geometryOptions: { type, controlPoints: controlPointsProp }, color }) => {
18
- let controlPoints = [...controlPointsProp];
19
- let measurementPoints: [Cartesian3, Cartesian3] | undefined;
20
- let showLine = false;
23
+ ({
24
+ geometryOptions: { type, controlPoints },
25
+ color,
26
+ isEditing,
27
+ catchedControlPointIndex,
28
+ selectedControlPointIndex,
29
+ handleControlPointMouseEvent,
30
+ }) => {
31
+ const measurements: { points: [Cartesian3, Cartesian3]; showLine: boolean }[] = [];
21
32
 
22
- if (type === "rectangle" && controlPoints.length === 3) {
23
- const [p1, p2, p3] = controlPoints;
24
- const projection = Cartesian3.projectVector(
25
- Cartesian3.subtract(p3, p1, cartesianScratch1),
26
- Cartesian3.subtract(p2, p1, cartesianScratch2),
27
- cartesianScratch1,
28
- );
29
- const offset = Cartesian3.subtract(
30
- p3,
31
- Cartesian3.add(p1, projection, cartesianScratch1),
32
- cartesianScratch2,
33
- );
34
- const p4 = Cartesian3.midpoint(p1, p2, cartesianScratch1);
35
- const p5 = Cartesian3.add(p4, offset, cartesianScratch2);
36
- controlPoints = [p1, p2, p5];
37
- measurementPoints = [p4, p5];
38
- showLine = true;
39
- } else if (type === "marker") {
40
- measurementPoints = undefined;
41
- controlPoints = [];
42
- } else if (controlPoints.length >= 2) {
43
- measurementPoints = controlPoints.slice(-2) as [Cartesian3, Cartesian3];
44
- showLine = type === "circle";
33
+ if (controlPoints.length >= 2) {
34
+ if (isEditing) {
35
+ if (catchedControlPointIndex !== undefined && catchedControlPointIndex !== -1) {
36
+ switch (type) {
37
+ case "polyline":
38
+ if (catchedControlPointIndex > 0) {
39
+ measurements.push({
40
+ points: [
41
+ controlPoints[catchedControlPointIndex - 1],
42
+ controlPoints[catchedControlPointIndex],
43
+ ],
44
+ showLine: false,
45
+ });
46
+ }
47
+ if (catchedControlPointIndex < controlPoints.length - 1) {
48
+ measurements.push({
49
+ points: [
50
+ controlPoints[catchedControlPointIndex],
51
+ controlPoints[catchedControlPointIndex + 1],
52
+ ],
53
+ showLine: false,
54
+ });
55
+ }
56
+ break;
57
+ case "circle":
58
+ case "extrudedCircle":
59
+ if (catchedControlPointIndex !== 2) {
60
+ measurements.push({
61
+ points: [controlPoints[0], controlPoints[1]],
62
+ showLine: true,
63
+ });
64
+ }
65
+ break;
66
+ case "rectangle":
67
+ case "extrudedRectangle":
68
+ if (catchedControlPointIndex <= 1) {
69
+ measurements.push({
70
+ points: [controlPoints[0], controlPoints[1]],
71
+ showLine: false,
72
+ });
73
+ } else if (catchedControlPointIndex === 2) {
74
+ const [p1, p2, p3] = controlPoints;
75
+ const p4 = Cartesian3.midpoint(p1, p2, cartesianScratch1);
76
+ measurements.push({ points: [p4, p3], showLine: true });
77
+ }
78
+ break;
79
+ case "polygon":
80
+ case "extrudedPolygon":
81
+ measurements.push({
82
+ points: [
83
+ controlPoints[catchedControlPointIndex],
84
+ catchedControlPointIndex === 0
85
+ ? controlPoints[controlPoints.length - 1]
86
+ : controlPoints[catchedControlPointIndex - 1],
87
+ ],
88
+ showLine: false,
89
+ });
90
+ measurements.push({
91
+ points: [
92
+ controlPoints[catchedControlPointIndex],
93
+ catchedControlPointIndex === controlPoints.length - 1
94
+ ? controlPoints[0]
95
+ : controlPoints[catchedControlPointIndex + 1],
96
+ ],
97
+ showLine: false,
98
+ });
99
+ break;
100
+ default:
101
+ break;
102
+ }
103
+ }
104
+ } else {
105
+ switch (type) {
106
+ case "rectangle" || "extrudedRectangle":
107
+ if (controlPoints.length === 2) {
108
+ measurements.push({
109
+ points: controlPoints as [Cartesian3, Cartesian3],
110
+ showLine: true,
111
+ });
112
+ } else if (controlPoints.length === 3) {
113
+ const [p1, p2, p3] = controlPoints;
114
+ const p4 = Cartesian3.midpoint(p1, p2, cartesianScratch1);
115
+ measurements.push({ points: [p4, p3], showLine: true });
116
+ }
117
+ break;
118
+ default:
119
+ measurements.push({
120
+ points: controlPoints.slice(-2) as [Cartesian3, Cartesian3],
121
+ showLine: type === "circle",
122
+ });
123
+ break;
124
+ }
125
+ }
45
126
  }
46
127
 
47
128
  return (
48
129
  <>
49
130
  {controlPoints.map((controlPoint, index) => (
50
- <ControlPoint key={index} position={controlPoint} clampToGround />
131
+ <ControlPoint
132
+ key={index}
133
+ position={controlPoint}
134
+ index={index}
135
+ isSelected={selectedControlPointIndex === index}
136
+ clampToGround
137
+ isEditing={isEditing}
138
+ handleControlPointMouseEvent={handleControlPointMouseEvent}
139
+ />
51
140
  ))}
52
- {measurementPoints != undefined && (
141
+ {measurements.map(({ points, showLine }, index) => (
53
142
  <SurfaceMeasurement
54
- a={measurementPoints[0]}
55
- b={measurementPoints[1]}
56
- color={color}
143
+ key={index}
144
+ a={points[0]}
145
+ b={points[1]}
146
+ color={isEditing ? Color.fromCssColorString(DEFAULT_EDIT_COLOR) : color}
57
147
  showLine={showLine}
58
148
  />
59
- )}
149
+ ))}
60
150
  </>
61
151
  );
62
152
  },
@@ -0,0 +1,5 @@
1
+ export const DEFAULT_SKETCH_COLOR = "#00bebe";
2
+
3
+ export const DEFAULT_EDIT_COLOR = "#3B3CD0";
4
+ export const SELECTED_EDIT_COLOR = "#FF9900";
5
+ export const ADDING_POINT_COLOR = "#3B3CD0";
@@ -2,46 +2,61 @@
2
2
 
3
3
  import { Color } from "@cesium/engine";
4
4
  import { Cartesian3 } from "cesium";
5
- import { type LineString, type MultiPolygon, type Polygon } from "geojson";
6
5
  import { memo, useMemo, type FC } from "react";
7
- import { type RequireExactlyOne } from "type-fest";
8
6
 
9
7
  import { SketchType } from "../../../Map/Sketch/types";
10
8
  import { Position3d } from "../../../types";
11
9
  import { convertGeometryToPositionsArray, convertPolygonToHierarchyArray } from "../utils/polygon";
12
10
 
11
+ import { DEFAULT_SKETCH_COLOR } from "./constants";
13
12
  import { createGeometry, GeometryOptions } from "./createGeometry";
14
13
  import ExtrudedControlPoints from "./ExtrudedControlPoints";
15
14
  import { ExtrudedPolygonEntity } from "./ExtrudedPolygonEntity";
16
15
  import { PolygonEntity } from "./PolygonEntity";
17
16
  import { PolylineEntity } from "./PolylineEntity";
17
+ import SurfaceAddingPoints from "./SurfaceAddingPoints";
18
18
  import SurfaceControlPoints from "./SurfaceControlPoints";
19
19
 
20
- export type SketchComponentProps = RequireExactlyOne<
21
- {
22
- geometry?: LineString | Polygon | MultiPolygon | null;
23
- geometryOptions?: {
24
- type: SketchType;
25
- controlPoints: readonly Position3d[];
26
- } | null;
27
- extrudedHeight?: number;
28
- disableShadow?: boolean;
29
- color?: string;
30
- enableRelativeHeight?: boolean;
31
- },
32
- "geometry" | "geometryOptions"
33
- >;
20
+ export type SketchComponentProps = {
21
+ geometryOptions?: {
22
+ type: SketchType;
23
+ controlPoints: readonly Position3d[];
24
+ } | null;
25
+ extrudedHeight?: number;
26
+ extrudedPoint?: Position3d;
27
+ centroidBasePoint?: Position3d;
28
+ centroidExtrudedPoint?: Position3d;
29
+ disableShadow?: boolean;
30
+ color?: string;
31
+ isEditing?: boolean;
32
+ catchedControlPointIndex?: number;
33
+ catchedExtrudedPoint?: boolean;
34
+ selectedControlPointIndex?: number;
35
+ handleControlPointMouseEvent?: ControlPointMouseEventHandler;
36
+ handleAddControlPoint?: (position: Position3d, index: number) => void;
37
+ };
34
38
 
35
- const DEFAULT_SKETCH_COLOR = "#00bebe";
39
+ export type ControlPointMouseEventHandler = (
40
+ index: number,
41
+ isExtrudedPoint: boolean,
42
+ type: "mousedown" | "click",
43
+ ) => void;
36
44
 
37
45
  const SketchComponent: FC<SketchComponentProps> = memo(
38
46
  ({
39
- geometry,
40
47
  geometryOptions,
41
48
  extrudedHeight,
42
49
  disableShadow,
43
50
  color: stringColor,
44
- enableRelativeHeight,
51
+ isEditing,
52
+ extrudedPoint,
53
+ centroidBasePoint,
54
+ centroidExtrudedPoint,
55
+ catchedControlPointIndex,
56
+ catchedExtrudedPoint,
57
+ selectedControlPointIndex,
58
+ handleControlPointMouseEvent,
59
+ handleAddControlPoint,
45
60
  }) => {
46
61
  const cartesianGeometryOptions: GeometryOptions | null = useMemo(
47
62
  () =>
@@ -55,9 +70,8 @@ const SketchComponent: FC<SketchComponentProps> = memo(
55
70
  );
56
71
 
57
72
  const g = useMemo(
58
- () =>
59
- geometry ?? (cartesianGeometryOptions ? createGeometry(cartesianGeometryOptions) : null),
60
- [geometry, cartesianGeometryOptions],
73
+ () => (cartesianGeometryOptions ? createGeometry(cartesianGeometryOptions) : null),
74
+ [cartesianGeometryOptions],
61
75
  );
62
76
 
63
77
  const { positionsArray, hierarchyArray } = useMemo(() => {
@@ -82,31 +96,56 @@ const SketchComponent: FC<SketchComponentProps> = memo(
82
96
  return (
83
97
  <>
84
98
  {positionsArray?.map((positions, index) => (
85
- <PolylineEntity key={index} dynamic positions={positions} color={color} />
99
+ <PolylineEntity
100
+ key={index}
101
+ dynamic
102
+ positions={positions}
103
+ color={color}
104
+ isEditing={isEditing}
105
+ />
86
106
  ))}
87
107
  {hierarchyArray?.map((hierarchy, index) => (
88
108
  <PolygonEntity key={index} dynamic hierarchy={hierarchy} color={color} />
89
109
  ))}
90
- {cartesianGeometryOptions != null && extrudedHeight == null && (
91
- <SurfaceControlPoints geometryOptions={cartesianGeometryOptions} color={color} />
110
+ {cartesianGeometryOptions != null && (!extrudedHeight || isEditing) && (
111
+ <SurfaceControlPoints
112
+ geometryOptions={cartesianGeometryOptions}
113
+ color={color}
114
+ isEditing={isEditing}
115
+ catchedControlPointIndex={catchedControlPointIndex}
116
+ selectedControlPointIndex={selectedControlPointIndex}
117
+ handleControlPointMouseEvent={handleControlPointMouseEvent}
118
+ />
119
+ )}
120
+ {cartesianGeometryOptions != null && isEditing && (
121
+ <SurfaceAddingPoints
122
+ geometryOptions={cartesianGeometryOptions}
123
+ isEditing={isEditing}
124
+ handleAddControlPoint={handleAddControlPoint}
125
+ />
92
126
  )}
93
- {cartesianGeometryOptions != null && extrudedHeight != null && (
127
+ {cartesianGeometryOptions != null && extrudedHeight && (
94
128
  <ExtrudedControlPoints
95
129
  geometryOptions={cartesianGeometryOptions}
96
130
  extrudedHeight={extrudedHeight}
131
+ extrudedPoint={extrudedPoint}
132
+ centroidBasePoint={centroidBasePoint}
133
+ centroidExtrudedPoint={centroidExtrudedPoint}
134
+ catchedExtrudedPoint={catchedExtrudedPoint}
97
135
  color={color}
136
+ isEditing={isEditing}
137
+ handleControlPointMouseEvent={handleControlPointMouseEvent}
98
138
  />
99
139
  )}
100
- {extrudedHeight != null &&
140
+ {extrudedHeight &&
101
141
  hierarchyArray?.map((hierarchy, index) => (
102
142
  <ExtrudedPolygonEntity
103
143
  key={index}
104
- dynamic
105
144
  hierarchy={hierarchy}
106
145
  extrudedHeight={extrudedHeight}
107
146
  disableShadow={disableShadow}
108
147
  color={color}
109
- enableRelativeHeight={enableRelativeHeight}
148
+ isEditing={isEditing}
110
149
  />
111
150
  ))}
112
151
  </>
@@ -5,7 +5,7 @@ import {
5
5
  IonResource,
6
6
  TerrainProvider,
7
7
  } from "cesium";
8
- import { useMemo } from "react";
8
+ import { useEffect, useMemo } from "react";
9
9
  import { Globe as CesiumGlobe } from "resium";
10
10
 
11
11
  import type { ViewerProperty, TerrainProperty } from "../..";
@@ -15,9 +15,14 @@ import { toColor } from "../common";
15
15
  export type Props = {
16
16
  property?: ViewerProperty;
17
17
  cesiumIonAccessToken?: string;
18
+ onTerrainProviderChange?: () => void;
18
19
  };
19
20
 
20
- export default function Globe({ property, cesiumIonAccessToken }: Props): JSX.Element | null {
21
+ export default function Globe({
22
+ property,
23
+ cesiumIonAccessToken,
24
+ onTerrainProviderChange,
25
+ }: Props): JSX.Element | null {
21
26
  const terrainProperty = useMemo(
22
27
  (): TerrainProperty => ({
23
28
  ...property?.terrain,
@@ -51,6 +56,10 @@ export default function Globe({ property, cesiumIonAccessToken }: Props): JSX.El
51
56
  [property?.globe?.baseColor],
52
57
  );
53
58
 
59
+ useEffect(() => {
60
+ onTerrainProviderChange?.();
61
+ }, [terrainProvider, onTerrainProviderChange]);
62
+
54
63
  return (
55
64
  <CesiumGlobe
56
65
  baseColor={baseColor}
@@ -5,7 +5,7 @@ import {
5
5
  TextureMinificationFilter,
6
6
  } from "cesium";
7
7
  import { isEqual } from "lodash-es";
8
- import { useCallback, useMemo, useRef, useLayoutEffect, useState } from "react";
8
+ import { useCallback, useMemo, useRef, useLayoutEffect, useState, useEffect } from "react";
9
9
  import { ImageryLayer } from "resium";
10
10
 
11
11
  import { tiles as tilePresets } from "./presets";
@@ -31,9 +31,10 @@ export type Tile = {
31
31
  export type Props = {
32
32
  tiles?: Tile[];
33
33
  cesiumIonAccessToken?: string;
34
+ onTilesChange?: () => void;
34
35
  };
35
36
 
36
- export default function ImageryLayers({ tiles, cesiumIonAccessToken }: Props) {
37
+ export default function ImageryLayers({ tiles, cesiumIonAccessToken, onTilesChange }: Props) {
37
38
  const { providers, updated } = useImageryProviders({
38
39
  tiles,
39
40
  cesiumIonAccessToken,
@@ -47,6 +48,10 @@ export default function ImageryLayers({ tiles, cesiumIonAccessToken }: Props) {
47
48
  if (updated) setCounter(c => c + 1);
48
49
  }, [providers, updated]);
49
50
 
51
+ useEffect(() => {
52
+ onTilesChange?.();
53
+ }, [tiles, counter, onTilesChange]);
54
+
50
55
  return (
51
56
  <>
52
57
  {tiles
@@ -24,17 +24,6 @@ export const tiles = {
24
24
  IonImageryProvider.fromAssetId(IonWorldImageryStyle.ROAD, {
25
25
  accessToken: cesiumIonAccessToken,
26
26
  }).catch(console.error),
27
- stamen_watercolor: () =>
28
- new OpenStreetMapImageryProvider({
29
- url: "https://stamen-tiles.a.ssl.fastly.net/watercolor/",
30
- credit: "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.",
31
- fileExtension: "jpg",
32
- }),
33
- stamen_toner: () =>
34
- new OpenStreetMapImageryProvider({
35
- url: "https://stamen-tiles.a.ssl.fastly.net/toner/",
36
- credit: "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under CC BY SA.",
37
- }),
38
27
  open_street_map: () =>
39
28
  new OpenStreetMapImageryProvider({
40
29
  url: "https://a.tile.openstreetmap.org/",
@@ -268,6 +268,21 @@ export default function useEngineRef(
268
268
  new Cesium.Cartesian2(windowPosition[0], windowPosition[1]),
269
269
  );
270
270
  },
271
+ getExtrudedPoint: (position, extrudedHeight) => {
272
+ if (!position || !extrudedHeight) return;
273
+ const viewer = cesium.current?.cesiumElement;
274
+ if (!viewer || viewer.isDestroyed()) return;
275
+ const point = new Cesium.Cartesian3(position[0], position[1], position[2]);
276
+ const cartesianScratch = new Cesium.Cartesian3();
277
+ const normal = viewer.scene?.globe.ellipsoid.geodeticSurfaceNormal(point, cartesianScratch);
278
+ if (!normal) return;
279
+ const extrudedPoint = Cesium.Cartesian3.add(
280
+ point,
281
+ Cesium.Cartesian3.multiplyByScalar(normal, extrudedHeight, cartesianScratch),
282
+ cartesianScratch,
283
+ );
284
+ return [extrudedPoint.x, extrudedPoint.y, extrudedPoint.z];
285
+ },
271
286
  getSurfaceDistance: (point1, point2) => {
272
287
  const viewer = cesium.current?.cesiumElement;
273
288
  if (!viewer || viewer.isDestroyed()) return;
@@ -938,6 +953,27 @@ export default function useEngineRef(
938
953
  tickEventCallback.current = tickEventCallback.current.filter(c => c !== cb) || [];
939
954
  },
940
955
  tickEventCallback,
956
+ calcRectangleControlPoint: (p1: Position3d, p2: Position3d, p3: Position3d) => {
957
+ const pp1 = new Cesium.Cartesian3(...p1);
958
+ const pp2 = new Cesium.Cartesian3(...p2);
959
+ const pp3 = new Cesium.Cartesian3(...p3);
960
+ const cartesianScratch1 = new Cesium.Cartesian3();
961
+ const cartesianScratch2 = new Cesium.Cartesian3();
962
+ const projection = Cesium.Cartesian3.projectVector(
963
+ Cesium.Cartesian3.subtract(pp3, pp1, cartesianScratch1),
964
+ Cesium.Cartesian3.subtract(pp2, pp1, cartesianScratch2),
965
+ cartesianScratch1,
966
+ );
967
+ const offset = Cesium.Cartesian3.subtract(
968
+ pp3,
969
+ Cesium.Cartesian3.add(pp1, projection, cartesianScratch1),
970
+ cartesianScratch2,
971
+ );
972
+ const pp4 = Cesium.Cartesian3.midpoint(pp1, pp2, cartesianScratch1);
973
+ const pp5 = Cesium.Cartesian3.add(pp4, offset, cartesianScratch2);
974
+ const p5 = [pp5.x, pp5.y, pp5.z] as Position3d;
975
+ return [p1, p2, p5];
976
+ },
941
977
  };
942
978
  }, [cesium]);
943
979
 
@@ -12,6 +12,8 @@ import {
12
12
  GroundPrimitive,
13
13
  ShadowMap,
14
14
  ImageryLayer,
15
+ CreditDisplay,
16
+ Credit as CesiumCredit,
15
17
  } from "cesium";
16
18
  import { MutableRefObject, RefObject, useCallback, useEffect, useMemo, useRef } from "react";
17
19
  import type { CesiumComponentRef, CesiumMovementEvent, RootEventTarget } from "resium";
@@ -27,6 +29,7 @@ import type {
27
29
  import { e2eAccessToken, setE2ECesiumViewer } from "../../e2eConfig";
28
30
  import { ComputedFeature, DataType, SelectedFeatureInfo, LatLng, Camera } from "../../mantle";
29
31
  import {
32
+ Credit,
30
33
  LayerLoadEvent,
31
34
  LayerSelectWithRectEnd,
32
35
  LayerSelectWithRectMove,
@@ -89,6 +92,7 @@ export default ({
89
92
  onLayerLoad,
90
93
  onCameraChange,
91
94
  onMount,
95
+ onCreditsUpdate,
92
96
  }: {
93
97
  ref: React.ForwardedRef<EngineRef>;
94
98
  property?: ViewerProperty;
@@ -128,6 +132,7 @@ export default ({
128
132
  onLayerLoad?: (e: LayerLoadEvent) => void;
129
133
  onCameraChange?: (camera: Camera) => void;
130
134
  onMount?: () => void;
135
+ onCreditsUpdate?: (credits: Credit[]) => void;
131
136
  }) => {
132
137
  const cesium = useRef<CesiumComponentRef<CesiumViewer>>(null);
133
138
 
@@ -728,6 +733,49 @@ export default ({
728
733
  unmountCamera?.();
729
734
  }, [unmountCamera]);
730
735
 
736
+ const updateCredits = useCallback(() => {
737
+ if (!onCreditsUpdate) return;
738
+ // currently we don't have a proper way to get the credits update event
739
+ // wait for 3 seconds to get latest credits
740
+ // some internal property is been used here.
741
+ setTimeout(() => {
742
+ const creditDisplay = cesium.current?.cesiumElement?.creditDisplay as
743
+ | (CreditDisplay & {
744
+ _currentFrameCredits: {
745
+ lightboxCredits: { _array: { credit?: CesiumCredit }[] };
746
+ screenCredits: { _array: { credit?: CesiumCredit }[] };
747
+ };
748
+ _currentCesiumCredit: CesiumCredit;
749
+ })
750
+ | undefined;
751
+
752
+ if (!creditDisplay) return;
753
+
754
+ const { lightboxCredits, screenCredits } = creditDisplay?._currentFrameCredits || {};
755
+ const cesiumCredits = creditDisplay._currentCesiumCredit;
756
+
757
+ const credits: Credit[] = [
758
+ ...(cesiumCredits?.html ? [{ html: cesiumCredits.html }] : []),
759
+ ...Array.from(lightboxCredits?._array ?? []).map(c => ({
760
+ html: c?.credit?.html,
761
+ })),
762
+ ...Array.from(screenCredits?._array ?? []).map(c => ({
763
+ html: c?.credit?.html,
764
+ })),
765
+ ];
766
+
767
+ onCreditsUpdate(credits);
768
+ }, 3000);
769
+ }, [onCreditsUpdate]);
770
+
771
+ const handleTilesChange = useCallback(() => {
772
+ updateCredits();
773
+ }, [updateCredits]);
774
+
775
+ const handleTerrainProviderChange = useCallback(() => {
776
+ updateCredits();
777
+ }, [updateCredits]);
778
+
731
779
  return {
732
780
  cesium,
733
781
  cesiumIonAccessToken,
@@ -747,6 +795,8 @@ export default ({
747
795
  handleClick,
748
796
  handleMount,
749
797
  handleUnmount,
798
+ handleTilesChange,
799
+ handleTerrainProviderChange,
750
800
  };
751
801
  };
752
802
 
@@ -47,6 +47,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
47
47
  shouldRender,
48
48
  layerSelectionReason,
49
49
  meta,
50
+ displayCredits,
50
51
  layersRef,
51
52
  featureFlags,
52
53
  requestingRenderMode,
@@ -63,6 +64,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
63
64
  onMount,
64
65
  onLayerVisibility,
65
66
  onLayerLoad,
67
+ onCreditsUpdate,
66
68
  },
67
69
  ref,
68
70
  ) => {
@@ -85,6 +87,8 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
85
87
  handleClick,
86
88
  handleMount,
87
89
  handleUnmount,
90
+ handleTilesChange,
91
+ handleTerrainProviderChange,
88
92
  } = useHooks({
89
93
  ref,
90
94
  property,
@@ -112,6 +116,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
112
116
  onLayerLoad,
113
117
  onCameraChange,
114
118
  onMount,
119
+ onCreditsUpdate,
115
120
  });
116
121
 
117
122
  return (
@@ -133,7 +138,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
133
138
  navigationHelpButton={false}
134
139
  projectionPicker={false}
135
140
  sceneModePicker={false}
136
- creditContainer={creditContainer}
141
+ creditContainer={displayCredits ? undefined : creditContainer}
137
142
  style={{
138
143
  width: small ? "300px" : "auto",
139
144
  height: small ? "300px" : "100%",
@@ -158,7 +163,11 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
158
163
  onWheel={mouseEventHandles.wheel}>
159
164
  <Event onMount={handleMount} onUnmount={handleUnmount} />
160
165
  <Clock timelineManagerRef={timelineManagerRef} />
161
- <ImageryLayers tiles={property?.tiles} cesiumIonAccessToken={cesiumIonAccessToken} />
166
+ <ImageryLayers
167
+ tiles={property?.tiles}
168
+ cesiumIonAccessToken={cesiumIonAccessToken}
169
+ onTilesChange={handleTilesChange}
170
+ />
162
171
  <LabelImageryLayers tileLabels={property?.tileLabels} />
163
172
  <Indicator property={property} timelineManagerRef={timelineManagerRef} />
164
173
  <ScreenSpaceEventHandler useDefault>
@@ -252,7 +261,11 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
252
261
  saturationShift={property?.sky?.skyAtmosphere?.saturationShift}
253
262
  brightnessShift={property?.sky?.skyAtmosphere?.brightnessShift}
254
263
  />
255
- <Globe property={property} cesiumIonAccessToken={cesiumIonAccessToken} />
264
+ <Globe
265
+ property={property}
266
+ cesiumIonAccessToken={cesiumIonAccessToken}
267
+ onTerrainProviderChange={handleTerrainProviderChange}
268
+ />
256
269
  <featureContext.Provider value={context}>{ready ? children : null}</featureContext.Provider>
257
270
  <AmbientOcclusion
258
271
  {...AMBIENT_OCCLUSION_QUALITY[property?.render?.ambientOcclusion?.quality || "low"]}