@reearth/core 0.0.7-alpha.61 → 0.0.7-alpha.63

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.
@@ -1,12 +1,16 @@
1
1
  import {
2
2
  Color,
3
+ ImageryLayer as CesiumImageryLayer,
3
4
  ImageryProvider,
4
5
  TextureMagnificationFilter,
5
6
  TextureMinificationFilter,
7
+ UrlTemplateImageryProvider,
6
8
  } from "cesium";
7
9
  import { isEqual } from "lodash-es";
8
- import { useCallback, useMemo, useRef, useLayoutEffect, useState, useEffect } from "react";
9
- import { ImageryLayer } from "resium";
10
+ import { useCallback, useMemo, useRef, useEffect } from "react";
11
+ import { useCesium } from "resium";
12
+
13
+ import type { CustomProviderConfig } from "../../../Map/types/customProvider";
10
14
 
11
15
  import { isValidPresetTileType, PresetTileType, tiles as tilePresets } from "./presets";
12
16
 
@@ -22,6 +26,7 @@ export type Tile = {
22
26
  id: string;
23
27
  url?: string;
24
28
  type?: string;
29
+ cesiumIonAssetId?: number;
25
30
  opacity?: number;
26
31
  zoomLevel?: number[];
27
32
  zoomLevelForURL?: number[];
@@ -31,64 +36,127 @@ export type Tile = {
31
36
  export type Props = {
32
37
  tiles?: Tile[];
33
38
  cesiumIonAccessToken?: string;
39
+ customProvider?: CustomProviderConfig;
34
40
  onTilesChange?: () => void;
35
41
  };
36
42
 
37
- export default function ImageryLayers({ tiles, cesiumIonAccessToken, onTilesChange }: Props) {
38
- const { providers, updated } = useImageryProviders({
43
+ // NOTE: This component intentionally bypasses Resium's declarative <ImageryLayer />.
44
+ // Resium wraps provider creation in queueMicrotask; under React 18 Strict Mode the effect
45
+ // cleanup runs before that microtask resolves, so the layer reference is undefined at cleanup
46
+ // time and old layers are never removed — they accumulate silently behind new ones.
47
+ // Direct imageryLayerCollection management with a `cancelled` flag is the only safe fix.
48
+ export default function ImageryLayers({
49
+ tiles,
50
+ cesiumIonAccessToken,
51
+ customProvider,
52
+ onTilesChange,
53
+ }: Props) {
54
+ const { imageryLayerCollection, scene } = useCesium();
55
+
56
+ const { providers } = useImageryProviders({
39
57
  tiles,
40
58
  cesiumIonAccessToken,
59
+ customProvider,
41
60
  presets: tilePresets,
42
61
  });
43
62
 
44
- // force rerendering all layers when any provider is updated
45
- // since Resium does not sort layers according to ImageryLayer component order
46
- const [counter, setCounter] = useState(0);
47
- useLayoutEffect(() => {
48
- if (updated) setCounter(c => c + 1);
49
- }, [providers, updated]);
50
-
51
63
  useEffect(() => {
64
+ if (!imageryLayerCollection || !scene) return;
65
+
66
+ let cancelled = false;
67
+ const addedLayers: CesiumImageryLayer[] = [];
68
+ // Track layers by their intended index to maintain order with async loading
69
+ const layersByIndex: (CesiumImageryLayer | null)[] = new Array(tiles?.length || 0).fill(null);
70
+
71
+ const reorderLayers = () => {
72
+ if (cancelled || scene.isDestroyed()) return;
73
+
74
+ // Move each layer to its correct position based on layersByIndex
75
+ layersByIndex.forEach((layer, targetIndex) => {
76
+ if (!layer) return;
77
+
78
+ const currentIndex = imageryLayerCollection.indexOf(layer);
79
+ if (currentIndex === -1) return; // Layer not in collection
80
+
81
+ // Calculate where this layer should be: count non-null layers before it
82
+ const desiredIndex = layersByIndex.slice(0, targetIndex).filter(l => l !== null).length;
83
+
84
+ if (currentIndex !== desiredIndex) {
85
+ // Move layer to correct position
86
+ imageryLayerCollection.remove(layer, false); // Don't destroy
87
+ imageryLayerCollection.add(layer, desiredIndex);
88
+ }
89
+ });
90
+
91
+ scene.requestRender();
92
+ };
93
+
94
+ tiles?.forEach(({ id, zoomLevel, opacity, heatmap }, i) => {
95
+ const providerOrPromise = providers[id]?.[3];
96
+ if (!providerOrPromise) return;
97
+
98
+ const doAdd = (provider: ImageryProvider) => {
99
+ if (!provider || cancelled || scene.isDestroyed()) return;
100
+ const layer = new CesiumImageryLayer(provider, {
101
+ minimumTerrainLevel: zoomLevel?.[0],
102
+ maximumTerrainLevel: zoomLevel?.[1],
103
+ alpha: opacity,
104
+ colorToAlpha: heatmap ? Color.WHITE : undefined,
105
+ colorToAlphaThreshold: heatmap ? 1 : undefined,
106
+ magnificationFilter: heatmap ? TextureMagnificationFilter.LINEAR : undefined,
107
+ minificationFilter: heatmap ? TextureMinificationFilter.NEAREST : undefined,
108
+ });
109
+
110
+ // Always append to avoid index out of bounds
111
+ imageryLayerCollection.add(layer);
112
+ layersByIndex[i] = layer;
113
+ addedLayers.push(layer);
114
+
115
+ // Reorder all layers after each addition
116
+ reorderLayers();
117
+ };
118
+
119
+ if (providerOrPromise instanceof Promise) {
120
+ providerOrPromise.then(doAdd).catch(err => console.error("Failed to load imagery provider:", err));
121
+ } else {
122
+ doAdd(providerOrPromise);
123
+ }
124
+ });
125
+
126
+ scene.requestRender();
52
127
  onTilesChange?.();
53
- }, [tiles, counter, onTilesChange]);
54
-
55
- return (
56
- <>
57
- {tiles
58
- ?.map(({ id, ...tile }) => ({
59
- ...tile,
60
- id,
61
- provider: providers[id]?.[2],
62
- }))
63
- .map(({ id, opacity, zoomLevel, provider, heatmap }, i) =>
64
- provider ? (
65
- <ImageryLayer
66
- key={`${id}_${i}_${counter}`}
67
- imageryProvider={provider}
68
- minimumTerrainLevel={zoomLevel?.[0]}
69
- maximumTerrainLevel={zoomLevel?.[1]}
70
- alpha={opacity}
71
- index={i}
72
- colorToAlpha={heatmap ? Color.WHITE : undefined}
73
- colorToAlphaThreshold={heatmap ? 1 : undefined}
74
- magnificationFilter={heatmap ? TextureMagnificationFilter.LINEAR : undefined}
75
- minificationFilter={heatmap ? TextureMinificationFilter.NEAREST : undefined}
76
- />
77
- ) : null,
78
- )}
79
- </>
80
- );
128
+
129
+ return () => {
130
+ cancelled = true;
131
+ for (const layer of addedLayers) {
132
+ if (!scene.isDestroyed() && imageryLayerCollection.contains(layer)) {
133
+ imageryLayerCollection.remove(layer);
134
+ }
135
+ }
136
+ };
137
+ }, [providers, tiles, imageryLayerCollection, scene, onTilesChange]);
138
+
139
+ return null;
81
140
  }
82
141
 
83
- type Providers = { [id: string]: [string | undefined, string | undefined, ImageryProvider] };
142
+ type Providers = {
143
+ [id: string]: [
144
+ string | undefined,
145
+ string | undefined,
146
+ number | undefined,
147
+ Promise<ImageryProvider> | ImageryProvider,
148
+ ];
149
+ };
84
150
 
85
151
  export function useImageryProviders({
86
152
  tiles = [],
87
153
  cesiumIonAccessToken,
154
+ customProvider,
88
155
  presets,
89
156
  }: {
90
157
  tiles?: Tile[];
91
158
  cesiumIonAccessToken?: string;
159
+ customProvider?: CustomProviderConfig;
92
160
  presets: {
93
161
  [K in PresetTileType]: (opts?: {
94
162
  url?: string;
@@ -99,17 +167,34 @@ export function useImageryProviders({
99
167
  };
100
168
  }): { providers: Providers; updated: boolean } {
101
169
  const newTile = useCallback(
102
- (t: Tile, ciat?: string) =>
103
- presets[isValidPresetTileType(t.type) ? t.type : "default"]({
170
+ (t: Tile, ciat?: string, tp?: CustomProviderConfig) => {
171
+ const opts = {
104
172
  url: t.url,
105
173
  cesiumIonAccessToken: ciat,
174
+ cesiumIonAssetId: t.cesiumIonAssetId,
106
175
  heatmap: t.heatmap,
107
- zoomLevel: t.zoomLevelForURL,
108
- }),
176
+ tile_zoomLevel: t.zoomLevelForURL,
177
+ };
178
+ if (isValidPresetTileType(t.type)) {
179
+ return presets[t.type](opts);
180
+ }
181
+ // Dynamic: check customProvider.imagery.providers for a matching id
182
+ const customEntry = tp?.imagery?.providers?.find(p => p.id === t.type);
183
+ if (customEntry) {
184
+ return new UrlTemplateImageryProvider({
185
+ url: customEntry.url,
186
+ credit: customEntry.credit,
187
+ maximumLevel: customEntry.maximumLevel,
188
+ minimumLevel: customEntry.minimumLevel,
189
+ });
190
+ }
191
+ return presets["open_street_map"](opts);
192
+ },
109
193
  [presets],
110
194
  );
111
195
 
112
196
  const prevCesiumIonAccessToken = useRef(cesiumIonAccessToken);
197
+ const prevCustomProvider = useRef(customProvider);
113
198
  const tileKeys = tiles.map(t => t.id).join(",");
114
199
  const prevTileKeys = useRef(tileKeys);
115
200
  const prevProviders = useRef<Providers>({});
@@ -123,9 +208,10 @@ export function useImageryProviders({
123
208
  );
124
209
  const prevZoomLevels = useRef(zoomLevels);
125
210
 
126
- // Manage TileProviders so that TileProvider does not need to be recreated each time tiles are updated.
211
+ // Manage CustomProviders so that CustomProvider does not need to be recreated each time tiles are updated.
127
212
  const { providers, updated } = useMemo(() => {
128
213
  const isCesiumAccessTokenUpdated = prevCesiumIonAccessToken.current !== cesiumIonAccessToken;
214
+ const isTileProviderUpdated = prevCustomProvider.current !== customProvider;
129
215
  const prevProvidersKeys = Object.keys(prevProviders.current);
130
216
  const added = tiles.map(t => t.id).filter(t => t && !prevProvidersKeys.includes(t));
131
217
 
@@ -137,7 +223,8 @@ export function useImageryProviders({
137
223
  added: added.includes(k),
138
224
  prevType: v?.[0],
139
225
  prevUrl: v?.[1],
140
- prevProvider: v?.[2],
226
+ prevIonAssetId: v?.[2],
227
+ prevProvider: v?.[3],
141
228
  tile: tiles.find(t => t.id === k),
142
229
  }));
143
230
 
@@ -149,6 +236,7 @@ export function useImageryProviders({
149
236
  added,
150
237
  prevType,
151
238
  prevUrl,
239
+ prevIonAssetId,
152
240
  prevProvider,
153
241
  tile,
154
242
  }):
@@ -157,6 +245,7 @@ export function useImageryProviders({
157
245
  [
158
246
  string | undefined,
159
247
  string | undefined,
248
+ number | undefined,
160
249
  Promise<ImageryProvider> | ImageryProvider | null | undefined,
161
250
  ],
162
251
  ]
@@ -168,30 +257,59 @@ export function useImageryProviders({
168
257
  added ||
169
258
  prevType !== tile.type ||
170
259
  prevUrl !== tile.url ||
171
- (isCesiumAccessTokenUpdated && (!tile.type || tile.type === "default"))
172
- ? [tile.type, tile.url, newTile(tile, cesiumIonAccessToken)]
173
- : [prevType, prevUrl, prevProvider],
260
+ prevIonAssetId !== tile.cesiumIonAssetId ||
261
+ isTileProviderUpdated ||
262
+ (isCesiumAccessTokenUpdated &&
263
+ (tile.type?.startsWith("cesium_ion") ||
264
+ tile.type === "default" ||
265
+ tile.type === "default_road" ||
266
+ tile.type === "default_label" ||
267
+ tile.type === "black_marble"))
268
+ ? [
269
+ tile.type,
270
+ tile.url,
271
+ tile.cesiumIonAssetId,
272
+ newTile(tile, cesiumIonAccessToken, customProvider),
273
+ ]
274
+ : [prevType, prevUrl, prevIonAssetId, prevProvider],
174
275
  ],
175
276
  )
176
277
  .filter(
177
- (e): e is [string, [string | undefined, string | undefined, ImageryProvider]] =>
178
- !!e?.[1][2],
278
+ (
279
+ e,
280
+ ): e is [
281
+ string,
282
+ [
283
+ string | undefined,
284
+ string | undefined,
285
+ number | undefined,
286
+ Promise<ImageryProvider> | ImageryProvider,
287
+ ],
288
+ ] => !!e?.[1][3],
179
289
  ),
180
290
  );
181
291
 
182
292
  const updated =
183
293
  !!added.length ||
184
294
  !!isCesiumAccessTokenUpdated ||
295
+ !!isTileProviderUpdated ||
185
296
  !isEqual(prevTileKeys.current, tileKeys) ||
186
297
  !isEqual(prevZoomLevels.current, zoomLevels) ||
187
- rawProviders.some(p => p.tile && (p.prevType !== p.tile.type || p.prevUrl !== p.tile.url));
298
+ rawProviders.some(
299
+ p =>
300
+ p.tile &&
301
+ (p.prevType !== p.tile.type ||
302
+ p.prevUrl !== p.tile.url ||
303
+ p.prevIonAssetId !== p.tile.cesiumIonAssetId),
304
+ );
188
305
 
189
306
  prevTileKeys.current = tileKeys;
190
307
  prevZoomLevels.current = zoomLevels;
191
308
  prevCesiumIonAccessToken.current = cesiumIonAccessToken;
309
+ prevCustomProvider.current = customProvider;
192
310
 
193
311
  return { providers, updated };
194
- }, [cesiumIonAccessToken, tiles, tileKeys, newTile, zoomLevels]);
312
+ }, [cesiumIonAccessToken, customProvider, tiles, tileKeys, newTile, zoomLevels]);
195
313
 
196
314
  prevProviders.current = providers;
197
315
  return { providers, updated };
@@ -11,13 +11,27 @@ import {
11
11
  import { JapanGSIOptimalBVmapLabelImageryProvider } from "./labels/JapanGSIOptimalBVmapVectorMapLabel/JapanGSIOptimalBVmapLabelImageryProvider";
12
12
 
13
13
  const PRESET_TILE_TYPES = [
14
- "default",
15
- "default_label",
16
- "default_road",
14
+ // Dynamic Cesium Ion asset — asset ID supplied per-tile via cesiumIonAssetId field
15
+ "cesium_ion",
16
+
17
+ // Public presets — always available, no auth required
17
18
  "open_street_map",
18
- "black_marble",
19
19
  "japan_gsi_standard",
20
+ "stamen_watercolor",
21
+ "carto_light",
20
22
  "url",
23
+
24
+ // Cesium Ion presets — require user-provided Ion token (scene.default.ion)
25
+ "cesium_ion_default",
26
+ "cesium_ion_labelled",
27
+ "cesium_ion_road",
28
+ "cesium_ion_earth_at_night",
29
+
30
+ // Legacy aliases — kept for backward compatibility with existing apps
31
+ "default", // → cesium_ion_default
32
+ "default_road", // → cesium_ion_road
33
+ "default_label", // → cesium_ion_labelled
34
+ "black_marble", // → cesium_ion_earth_at_night
21
35
  ];
22
36
 
23
37
  export type PresetTileType = (typeof PRESET_TILE_TYPES)[number];
@@ -26,35 +40,61 @@ export const isValidPresetTileType = (type: string | undefined): type is PresetT
26
40
  return PRESET_TILE_TYPES.includes(type as PresetTileType);
27
41
  };
28
42
 
43
+ export type TileOptions = {
44
+ url?: string;
45
+ cesiumIonAccessToken?: string;
46
+ cesiumIonAssetId?: number | string;
47
+ heatmap?: boolean;
48
+ tile_zoomLevel?: number[];
49
+ };
50
+
29
51
  export const tiles = {
30
- default: ({ cesiumIonAccessToken } = {}) =>
31
- IonImageryProvider.fromAssetId(IonWorldImageryStyle.AERIAL, {
32
- accessToken: cesiumIonAccessToken,
33
- }).catch(console.error),
34
- default_label: ({ cesiumIonAccessToken } = {}) =>
35
- IonImageryProvider.fromAssetId(IonWorldImageryStyle.AERIAL_WITH_LABELS, {
36
- accessToken: cesiumIonAccessToken,
37
- }).catch(console.error),
38
- default_road: ({ cesiumIonAccessToken } = {}) =>
39
- IonImageryProvider.fromAssetId(IonWorldImageryStyle.ROAD, {
40
- accessToken: cesiumIonAccessToken,
41
- }).catch(console.error),
52
+ // --- Dynamic Cesium Ion asset ---
53
+ // Uses per-tile cesiumIonAssetId; requires cesiumIonAccessToken.
54
+ cesium_ion: (opts?: TileOptions) => {
55
+ if (!opts?.cesiumIonAssetId) return null;
56
+ const NumberAssetId = parseInt(String(opts.cesiumIonAssetId), 10);
57
+ if (isNaN(NumberAssetId)) {
58
+ console.warn(`Invalid cesiumIonAssetId: ${opts.cesiumIonAssetId}`);
59
+ return null;
60
+ }
61
+ return IonImageryProvider.fromAssetId(NumberAssetId, {
62
+ accessToken: opts?.cesiumIonAccessToken,
63
+ }).catch(err => {
64
+ console.error(err);
65
+ return undefined as unknown as ImageryProvider;
66
+ });
67
+ },
68
+
69
+ // --- Public presets ---
42
70
  open_street_map: () =>
43
71
  new OpenStreetMapImageryProvider({
44
72
  url: "https://tile.openstreetmap.org",
45
73
  credit: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
46
74
  }),
47
- black_marble: ({ cesiumIonAccessToken } = {}) =>
48
- IonImageryProvider.fromAssetId(3812, {
49
- accessToken: cesiumIonAccessToken,
50
- }).catch(console.error),
75
+
51
76
  japan_gsi_standard: () =>
52
77
  new OpenStreetMapImageryProvider({
53
78
  url: "https://cyberjapandata.gsi.go.jp/xyz/std/",
54
79
  credit:
55
80
  "<a href='https://maps.gsi.go.jp/development/ichiran.html'>国土地理院</a>, Shoreline data is derived from: United States. National Imagery and Mapping Agency. \"Vector Map Level 0 (VMAP0).\" Bethesda, MD: Denver, CO: The Agency; USGS Information Services, 1997.",
56
81
  }),
57
- url: ({ url, heatmap, tile_zoomLevel } = {}) =>
82
+
83
+ stamen_watercolor: () =>
84
+ new UrlTemplateImageryProvider({
85
+ url: "https://watercolormaps.collection.cooperhewitt.org/tile/watercolor/{z}/{x}/{y}.jpg",
86
+ credit: "Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL.",
87
+ maximumLevel: 16,
88
+ }),
89
+
90
+ carto_light: () =>
91
+ new UrlTemplateImageryProvider({
92
+ url: "https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
93
+ credit:
94
+ "© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors, © <a href='https://carto.com/attributions'>CARTO</a>",
95
+ }),
96
+
97
+ url: ({ url, heatmap, tile_zoomLevel }: TileOptions = {}) =>
58
98
  url
59
99
  ? new UrlTemplateImageryProvider({
60
100
  url,
@@ -63,15 +103,53 @@ export const tiles = {
63
103
  maximumLevel: tile_zoomLevel?.[1],
64
104
  })
65
105
  : null,
66
- } as {
67
- [K in PresetTileType]: (opts?: {
68
- url?: string;
69
- cesiumIonAccessToken?: string;
70
- heatmap?: boolean;
71
- tile_zoomLevel?: number[];
72
- }) => Promise<ImageryProvider> | ImageryProvider | null;
106
+
107
+ // --- Cesium Ion presets ---
108
+ // Require the user to configure a Cesium Ion access token in their scene (scene.default.ion).
109
+ cesium_ion_default: (opts?: TileOptions) =>
110
+ IonImageryProvider.fromAssetId(IonWorldImageryStyle.AERIAL, {
111
+ accessToken: opts?.cesiumIonAccessToken,
112
+ }).catch(err => {
113
+ console.error(err);
114
+ return undefined as unknown as ImageryProvider;
115
+ }),
116
+
117
+ cesium_ion_labelled: (opts?: TileOptions) =>
118
+ IonImageryProvider.fromAssetId(IonWorldImageryStyle.AERIAL_WITH_LABELS, {
119
+ accessToken: opts?.cesiumIonAccessToken,
120
+ }).catch(err => {
121
+ console.error(err);
122
+ return undefined as unknown as ImageryProvider;
123
+ }),
124
+
125
+ cesium_ion_road: (opts?: TileOptions) =>
126
+ IonImageryProvider.fromAssetId(IonWorldImageryStyle.ROAD, {
127
+ accessToken: opts?.cesiumIonAccessToken,
128
+ }).catch(err => {
129
+ console.error(err);
130
+ return undefined as unknown as ImageryProvider;
131
+ }),
132
+
133
+ cesium_ion_earth_at_night: (opts?: TileOptions) =>
134
+ IonImageryProvider.fromAssetId(3812, {
135
+ accessToken: opts?.cesiumIonAccessToken,
136
+ }).catch(err => {
137
+ console.error(err);
138
+ return undefined as unknown as ImageryProvider;
139
+ }),
140
+ // --- Legacy aliases ---
141
+ } as any as {
142
+ [K in PresetTileType]: (opts?: TileOptions) => Promise<ImageryProvider> | ImageryProvider | null;
73
143
  };
74
144
 
145
+ // Populate legacy aliases after object literal to allow forward references.
146
+ Object.assign(tiles, {
147
+ default: tiles.cesium_ion_default,
148
+ default_road: tiles.cesium_ion_road,
149
+ default_label: tiles.cesium_ion_labelled,
150
+ black_marble: tiles.cesium_ion_earth_at_night,
151
+ });
152
+
75
153
  export const labelTiles = {
76
154
  japan_gsi_optimal_bvmap: (params: {
77
155
  url: string;
@@ -42,23 +42,23 @@ const defaultMatcher = new StringMatcher()
42
42
  #endif
43
43
  vec4 color = computeDayColor(initialColor`,
44
44
  );
45
- // Note: Commented out erase() call as it's not needed for Cesium 1.118.x
46
- // The replace() above already handles the material code modification
47
- // .erase([
48
- // "#ifdef APPLY_MATERIAL",
49
- // "czm_materialInput materialInput;",
50
- // "materialInput.st = v_textureCoordinates.st;",
51
- // "materialInput.normalEC = normalize(v_normalEC);",
52
- // "materialInput.positionToEyeEC = -v_positionEC;",
53
- // "materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalize(v_normalEC));",
54
- // "materialInput.slope = v_slope;",
55
- // "materialInput.height = v_height;",
56
- // "materialInput.aspect = v_aspect;",
57
- // "czm_material material = czm_getMaterial(materialInput);",
58
- // "vec4 materialColor = vec4(material.diffuse, material.alpha);",
59
- // "color = alphaBlend(materialColor, color);",
60
- // "#endif",
61
- // ]);
45
+ // Note: Commented out erase() call as it's not needed for Cesium 1.118.x
46
+ // The replace() above already handles the material code modification
47
+ // .erase([
48
+ // "#ifdef APPLY_MATERIAL",
49
+ // "czm_materialInput materialInput;",
50
+ // "materialInput.st = v_textureCoordinates.st;",
51
+ // "materialInput.normalEC = normalize(v_normalEC);",
52
+ // "materialInput.positionToEyeEC = -v_positionEC;",
53
+ // "materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, normalize(v_normalEC));",
54
+ // "materialInput.slope = v_slope;",
55
+ // "materialInput.height = v_height;",
56
+ // "materialInput.aspect = v_aspect;",
57
+ // "czm_material material = czm_getMaterial(materialInput);",
58
+ // "vec4 materialColor = vec4(material.diffuse, material.alpha);",
59
+ // "color = alphaBlend(materialColor, color);",
60
+ // "#endif",
61
+ // ]);
62
62
 
63
63
  function makeGlobeShadersDirty(globe: Globe): void {
64
64
  // Invoke the internal makeShadersDirty() by setting a material to globe to
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  Entity,
3
3
  Cesium3DTileFeature,
4
- Ion,
5
4
  Cesium3DTileset,
6
5
  JulianDate,
7
6
  Cesium3DTilePointFeature,
@@ -28,6 +27,7 @@ import { e2eAccessToken, setE2ECesiumViewer } from "../../e2eConfig";
28
27
  import { ComputedFeature, DataType, SelectedFeatureInfo, LatLng, Camera } from "../../mantle";
29
28
  import {
30
29
  Credits,
30
+ CustomProviderConfig,
31
31
  LayerLoadEvent,
32
32
  LayerSelectWithRectEnd,
33
33
  LayerSelectWithRectMove,
@@ -70,6 +70,7 @@ export default ({
70
70
  selectedLayerId,
71
71
  selectionReason,
72
72
  meta,
73
+ customProvider,
73
74
  layersRef,
74
75
  featureFlags,
75
76
  timelineManagerRef,
@@ -102,6 +103,7 @@ export default ({
102
103
  layersRef?: RefObject<LayersRef | null>;
103
104
  selectionReason?: LayerSelectionReason;
104
105
  meta?: Record<string, unknown>;
106
+ customProvider?: CustomProviderConfig;
105
107
  featureFlags: number;
106
108
  timelineManagerRef?: TimelineManagerRef;
107
109
  isLayerDraggable?: boolean;
@@ -137,7 +139,7 @@ export default ({
137
139
  const cesiumIonAccessToken =
138
140
  typeof meta?.cesiumIonAccessToken === "string" && meta.cesiumIonAccessToken
139
141
  ? meta.cesiumIonAccessToken
140
- : Ion.defaultAccessToken;
142
+ : undefined;
141
143
 
142
144
  // expose ref
143
145
  const engineAPI = useEngineRef(ref, cesium);
@@ -674,6 +676,7 @@ export default ({
674
676
  () => ({
675
677
  selectionReason,
676
678
  timelineManagerRef,
679
+ customProvider,
677
680
  flyTo: engineAPI.flyTo,
678
681
  getCamera: engineAPI.getCamera,
679
682
  onLayerEdit,
@@ -688,11 +691,12 @@ export default ({
688
691
  }),
689
692
  [
690
693
  selectionReason,
694
+ timelineManagerRef,
695
+ customProvider,
691
696
  engineAPI,
692
697
  onLayerEdit,
693
698
  onLayerVisibility,
694
699
  onLayerLoad,
695
- timelineManagerRef,
696
700
  updateCredits,
697
701
  ],
698
702
  );
@@ -730,7 +734,13 @@ export default ({
730
734
 
731
735
  useLayerDragDrop({ cesium, onLayerDrag, onLayerDrop, isLayerDraggable });
732
736
 
733
- useExplicitRender({ cesium, requestingRenderMode, isLayerDragging, shouldRender, property });
737
+ useExplicitRender({
738
+ cesium,
739
+ requestingRenderMode,
740
+ isLayerDragging,
741
+ shouldRender,
742
+ property,
743
+ });
734
744
 
735
745
  const {
736
746
  cameraViewBoundaries,
@@ -47,6 +47,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
47
47
  shouldRender,
48
48
  layerSelectionReason,
49
49
  meta,
50
+ customProvider,
50
51
  displayCredits,
51
52
  layersRef,
52
53
  featureFlags,
@@ -96,6 +97,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
96
97
  selectedLayerId,
97
98
  selectionReason: layerSelectionReason,
98
99
  meta,
100
+ customProvider,
99
101
  layersRef,
100
102
  featureFlags,
101
103
  timelineManagerRef,
@@ -167,6 +169,7 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
167
169
  <ImageryLayers
168
170
  tiles={property?.tiles}
169
171
  cesiumIonAccessToken={cesiumIonAccessToken}
172
+ customProvider={customProvider}
170
173
  onTilesChange={handleTilesChange}
171
174
  />
172
175
  <LabelImageryLayers tileLabels={property?.tileLabels} />
@@ -293,5 +296,14 @@ export const engine: Engine = {
293
296
  featureComponent: Feature,
294
297
  clusterComponent: Cluster,
295
298
  sketchComponent: Sketch,
296
- delegatedDataTypes: ["czml", "wms", "mvt", "3dtiles", "osm-buildings", "kml"],
299
+ delegatedDataTypes: [
300
+ "czml",
301
+ "wms",
302
+ "mvt",
303
+ "3dtiles",
304
+ "osm-buildings",
305
+ "reearth-buildings",
306
+ "google-photorealistic",
307
+ "kml",
308
+ ],
297
309
  };
@@ -76,6 +76,7 @@ export type Data = {
76
76
  updateInterval?: number; // milliseconds
77
77
  parameters?: Record<string, any>;
78
78
  idProperty?: string;
79
+ provider?: string;
79
80
  serviceTokens?: {
80
81
  googleMapApiKey?: string;
81
82
  };
@@ -107,6 +108,7 @@ export type DataType =
107
108
  | "geojson"
108
109
  | "3dtiles"
109
110
  | "osm-buildings"
111
+ | "reearth-buildings"
110
112
  | "google-photorealistic"
111
113
  | "czml"
112
114
  | "csv"