@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.
- package/dist/core.js +62227 -67250
- package/dist/core.umd.cjs +682 -662
- package/dist/{index-CUJ6HGQn.js → index-DqGWVPtz.js} +907 -1021
- package/dist/index.d.ts +62 -56
- package/package.json +1 -1
- package/src/Map/Layers/hooks.ts +10 -4
- package/src/Map/Sketch/sketchMachine.ts +473 -395
- package/src/Map/types/customProvider.ts +32 -0
- package/src/Map/types/index.ts +3 -0
- package/src/Map/types/viewerProperty.ts +2 -1
- package/src/Visualizer/index.tsx +4 -0
- package/src/engines/Cesium/Feature/Tileset/hooks.ts +50 -22
- package/src/engines/Cesium/Feature/context.ts +2 -0
- package/src/engines/Cesium/Feature/index.tsx +1 -0
- package/src/engines/Cesium/core/Globe/index.tsx +1 -5
- package/src/engines/Cesium/core/Globe/useTerrainProviderPromise.ts +18 -16
- package/src/engines/Cesium/core/Imagery.test.ts +79 -44
- package/src/engines/Cesium/core/Imagery.tsx +171 -53
- package/src/engines/Cesium/core/presets.ts +106 -28
- package/src/engines/Cesium/hooks/useOverrideGlobeShader/useOverrideGlobeShader.ts +17 -17
- package/src/engines/Cesium/hooks.ts +14 -4
- package/src/engines/Cesium/index.tsx +13 -1
- package/src/mantle/types/index.ts +2 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic provider configuration for overriding external data sources.
|
|
3
|
+
*
|
|
4
|
+
* - imagery.providers: imagery tile providers keyed by id
|
|
5
|
+
* - layers.providers: 3D tileset providers keyed by id
|
|
6
|
+
*
|
|
7
|
+
* Terrain is configured via viewer/engine terrain settings (see useTerrainProviderPromise)
|
|
8
|
+
* or via each layer's own `url` field.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type ImageryProviderEntry = {
|
|
12
|
+
id: string;
|
|
13
|
+
url: string;
|
|
14
|
+
credit?: string;
|
|
15
|
+
maximumLevel?: number;
|
|
16
|
+
minimumLevel?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type LayerProviderEntry = {
|
|
20
|
+
id: string;
|
|
21
|
+
url: string;
|
|
22
|
+
options?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type CustomProviderConfig = {
|
|
26
|
+
imagery?: {
|
|
27
|
+
providers?: ImageryProviderEntry[];
|
|
28
|
+
};
|
|
29
|
+
layers?: {
|
|
30
|
+
providers?: LayerProviderEntry[];
|
|
31
|
+
};
|
|
32
|
+
};
|
package/src/Map/types/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
} from "../Sketch/types";
|
|
48
48
|
import type { TimelineManagerRef } from "../useTimelineManager";
|
|
49
49
|
|
|
50
|
+
import type { CustomProviderConfig } from "./customProvider";
|
|
50
51
|
import type { SceneMode, ViewerProperty } from "./viewerProperty";
|
|
51
52
|
|
|
52
53
|
export type {
|
|
@@ -79,6 +80,7 @@ export type {
|
|
|
79
80
|
} from "../../mantle";
|
|
80
81
|
export * from "./event";
|
|
81
82
|
export * from "./viewerProperty";
|
|
83
|
+
export * from "./customProvider";
|
|
82
84
|
|
|
83
85
|
export type EngineRef = {
|
|
84
86
|
name: string;
|
|
@@ -237,6 +239,7 @@ export type EngineProps = {
|
|
|
237
239
|
isLayerDragging?: boolean;
|
|
238
240
|
shouldRender?: boolean;
|
|
239
241
|
meta?: Record<string, unknown>;
|
|
242
|
+
customProvider?: CustomProviderConfig;
|
|
240
243
|
displayCredits?: boolean;
|
|
241
244
|
layersRef?: RefObject<LayersRef | null>;
|
|
242
245
|
requestingRenderMode?: MutableRefObject<RequestingRenderMode>;
|
|
@@ -74,7 +74,7 @@ export type GlobeAtmosphereProperty = {
|
|
|
74
74
|
|
|
75
75
|
export type TerrainProperty = {
|
|
76
76
|
enabled?: boolean;
|
|
77
|
-
type?: "cesium" | "
|
|
77
|
+
type?: "cesium" | "cesiumion" | "reearth_terrain";
|
|
78
78
|
url?: string;
|
|
79
79
|
normal?: boolean;
|
|
80
80
|
elevationHeatMap?: ElevationHeatMapProperty;
|
|
@@ -130,6 +130,7 @@ export type TileProperty = {
|
|
|
130
130
|
id: string;
|
|
131
131
|
type?: string;
|
|
132
132
|
url?: string;
|
|
133
|
+
cesiumIonAssetId?: number;
|
|
133
134
|
opacity?: number;
|
|
134
135
|
zoomLevel?: number[];
|
|
135
136
|
zoomLevelForURL?: number[];
|
package/src/Visualizer/index.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type Cluster,
|
|
14
14
|
type ComputedLayer,
|
|
15
15
|
type Credits,
|
|
16
|
+
type CustomProviderConfig,
|
|
16
17
|
} from "../Map";
|
|
17
18
|
import { SketchFeature, SketchType } from "../Map/Sketch/types";
|
|
18
19
|
import type { InteractionModeType } from "../shared/interactionMode";
|
|
@@ -42,6 +43,7 @@ export type CoreVisualizerProps = {
|
|
|
42
43
|
interactionMode?: InteractionModeType;
|
|
43
44
|
shouldRender?: boolean;
|
|
44
45
|
meta?: Record<string, unknown>;
|
|
46
|
+
customProvider?: CustomProviderConfig;
|
|
45
47
|
style?: CSSProperties;
|
|
46
48
|
small?: boolean;
|
|
47
49
|
ready?: boolean;
|
|
@@ -85,6 +87,7 @@ export const CoreVisualizer = memo(
|
|
|
85
87
|
interactionMode,
|
|
86
88
|
shouldRender,
|
|
87
89
|
meta,
|
|
90
|
+
customProvider,
|
|
88
91
|
displayCredits = true,
|
|
89
92
|
style,
|
|
90
93
|
zoomedLayerId,
|
|
@@ -165,6 +168,7 @@ export const CoreVisualizer = memo(
|
|
|
165
168
|
isLayerDragging={isLayerDragging}
|
|
166
169
|
isLayerDraggable={isEditable}
|
|
167
170
|
meta={meta}
|
|
171
|
+
customProvider={customProvider}
|
|
168
172
|
displayCredits={displayCredits}
|
|
169
173
|
style={style}
|
|
170
174
|
featureFlags={featureFlags}
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Cesium3DTileset as Cesium3DTilesetType,
|
|
3
3
|
Cesium3DTileStyle,
|
|
4
4
|
IonResource,
|
|
5
|
+
Resource,
|
|
5
6
|
ClippingPlane,
|
|
6
7
|
ClippingPlaneCollection as CesiumClippingPlaneCollection,
|
|
7
8
|
Cartesian3,
|
|
@@ -75,6 +76,7 @@ const useData = (layer: ComputedLayer | undefined) => {
|
|
|
75
76
|
: data?.layers
|
|
76
77
|
: undefined,
|
|
77
78
|
googleMapApiKey: data?.serviceTokens?.googleMapApiKey,
|
|
79
|
+
provider: data?.provider,
|
|
78
80
|
};
|
|
79
81
|
}, [layer]);
|
|
80
82
|
};
|
|
@@ -457,7 +459,7 @@ export const useHooks = ({
|
|
|
457
459
|
}) => {
|
|
458
460
|
const { viewer } = useCesium();
|
|
459
461
|
const tilesetRef = useRef<Cesium3DTilesetType>(undefined);
|
|
460
|
-
const { onLayerLoad, updateCredits } = useContext();
|
|
462
|
+
const { onLayerLoad, updateCredits, customProvider } = useContext();
|
|
461
463
|
const layerIdRef = useRef(layer?.id);
|
|
462
464
|
layerIdRef.current = layer?.id;
|
|
463
465
|
|
|
@@ -487,7 +489,7 @@ export const useHooks = ({
|
|
|
487
489
|
} = useClippingBox({ clipping: experimental_clipping, boxId });
|
|
488
490
|
|
|
489
491
|
const [style, setStyle] = useState<Cesium3DTileStyle>();
|
|
490
|
-
const { url, type, idProperty, googleMapApiKey } = useData(layer);
|
|
492
|
+
const { url, type, idProperty, googleMapApiKey, provider } = useData(layer);
|
|
491
493
|
const shouldUseFeatureIndex = !disableIndexingFeature && !!idProperty;
|
|
492
494
|
|
|
493
495
|
const [isTilesetReady, setIsTilesetReady] = useState(false);
|
|
@@ -752,20 +754,30 @@ export const useHooks = ({
|
|
|
752
754
|
}
|
|
753
755
|
}, [style, isTilesetReady]);
|
|
754
756
|
|
|
755
|
-
const googleMapPhotorealisticResource = useMemo(() => {
|
|
757
|
+
const googleMapPhotorealisticResource = useMemo((): string | Promise<Resource> | null => {
|
|
756
758
|
if (type !== "google-photorealistic" || !isVisible) return null;
|
|
757
759
|
|
|
758
|
-
|
|
760
|
+
// For Re:Earth provider, use the custom URL from customProvider or layer data
|
|
761
|
+
if (provider === "reearth") {
|
|
762
|
+
// Try to get URL from customProvider first, then fall back to layer URL
|
|
763
|
+
const customUrl = customProvider?.layers?.providers?.find(
|
|
764
|
+
p => p.id === "reearth_google_photorealistic_3d_tiles",
|
|
765
|
+
)?.url;
|
|
766
|
+
|
|
767
|
+
return customUrl || url || null;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Otherwise load via Google API key or Cesium Ion.
|
|
771
|
+
const loadTileset = async (): Promise<Resource> => {
|
|
759
772
|
try {
|
|
760
|
-
if (googleMapApiKey) {
|
|
761
|
-
const
|
|
762
|
-
return tileset.resource;
|
|
763
|
-
} else {
|
|
764
|
-
const resource = IonResource.fromAssetId(2275207, {
|
|
773
|
+
if (provider === "cesium-ion" || !googleMapApiKey) {
|
|
774
|
+
const resource = await IonResource.fromAssetId(2275207, {
|
|
765
775
|
accessToken: meta?.cesiumIonAccessToken as string | undefined,
|
|
766
776
|
});
|
|
767
777
|
return resource;
|
|
768
778
|
}
|
|
779
|
+
const tileset = await createGooglePhotorealistic3DTileset({ key: googleMapApiKey });
|
|
780
|
+
return tileset.resource;
|
|
769
781
|
} catch (error) {
|
|
770
782
|
console.error(`Error loading Photorealistic 3D Tiles tileset: ${error}`);
|
|
771
783
|
throw error;
|
|
@@ -773,19 +785,35 @@ export const useHooks = ({
|
|
|
773
785
|
};
|
|
774
786
|
|
|
775
787
|
return loadTileset();
|
|
776
|
-
}, [type, isVisible, googleMapApiKey, meta?.cesiumIonAccessToken]);
|
|
777
|
-
|
|
778
|
-
const tilesetUrl = useMemo(() => {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
788
|
+
}, [type, isVisible, googleMapApiKey, meta?.cesiumIonAccessToken, provider, customProvider, url]);
|
|
789
|
+
|
|
790
|
+
const tilesetUrl = useMemo((): string | Resource | Promise<Resource> | null => {
|
|
791
|
+
if (!isVisible) return null;
|
|
792
|
+
|
|
793
|
+
// Google Photorealistic 3D Tiles
|
|
794
|
+
if (googleMapPhotorealisticResource) {
|
|
795
|
+
return googleMapPhotorealisticResource;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// Re:Earth Buildings — use layer's own url if provided, otherwise fall back to public service
|
|
799
|
+
if (type === "reearth-buildings") {
|
|
800
|
+
return url ?? "https://buildings.reearth.land/tileset.json";
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// OSM Buildings — only available via Cesium Ion.
|
|
804
|
+
if (type === "osm-buildings") {
|
|
805
|
+
return IonResource.fromAssetId(96188, {
|
|
806
|
+
accessToken: meta?.cesiumIonAccessToken as string | undefined,
|
|
807
|
+
}); // https://github.com/CesiumGS/cesium/blob/main/packages/engine/Source/Scene/createOsmBuildings.js#L53
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Standard 3D Tiles with explicit URL
|
|
811
|
+
if (type === "3dtiles") {
|
|
812
|
+
return url ?? tileset ?? null;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
return null;
|
|
816
|
+
}, [type, isVisible, googleMapPhotorealisticResource, url, tileset, meta?.cesiumIonAccessToken]);
|
|
789
817
|
|
|
790
818
|
const imageBasedLighting = useMemo(() => {
|
|
791
819
|
if (
|
|
@@ -3,12 +3,14 @@ import { createContext, useContext as useReactContext } from "react";
|
|
|
3
3
|
|
|
4
4
|
import type { Camera, LayerSelectionReason } from "../..";
|
|
5
5
|
import { LayerEditEvent, LayerLoadEvent, LayerVisibilityEvent } from "../../../Map";
|
|
6
|
+
import type { CustomProviderConfig } from "../../../Map/types/customProvider";
|
|
6
7
|
import { TimelineManagerRef } from "../../../Map/useTimelineManager";
|
|
7
8
|
import type { FlyTo } from "../../../types";
|
|
8
9
|
|
|
9
10
|
export type Context = {
|
|
10
11
|
selectionReason?: LayerSelectionReason;
|
|
11
12
|
timelineManagerRef?: TimelineManagerRef;
|
|
13
|
+
customProvider?: CustomProviderConfig;
|
|
12
14
|
getCamera?: () => Camera | undefined;
|
|
13
15
|
flyTo?: FlyTo;
|
|
14
16
|
onLayerEdit?: (e: LayerEditEvent) => void;
|
|
@@ -65,6 +65,7 @@ const displayConfig: Record<DataType, (keyof typeof components)[] | "auto"> = {
|
|
|
65
65
|
tms: ["raster"],
|
|
66
66
|
"3dtiles": ["3dtiles"],
|
|
67
67
|
"osm-buildings": ["3dtiles"],
|
|
68
|
+
"reearth-buildings": ["3dtiles"],
|
|
68
69
|
"google-photorealistic": ["3dtiles"],
|
|
69
70
|
gpx: "auto",
|
|
70
71
|
shapefile: "auto",
|
|
@@ -39,17 +39,13 @@ export default function Globe({
|
|
|
39
39
|
providerPromise
|
|
40
40
|
.then(resolvedProvider => {
|
|
41
41
|
if (isCancelled) return;
|
|
42
|
-
|
|
43
|
-
// Only trigger callback if the resolved provider is actually different
|
|
44
42
|
if (lastResolvedProviderRef.current !== resolvedProvider) {
|
|
45
43
|
lastResolvedProviderRef.current = resolvedProvider;
|
|
46
44
|
onTerrainProviderChange?.();
|
|
47
45
|
}
|
|
48
46
|
})
|
|
49
47
|
.catch(error => {
|
|
50
|
-
if (!isCancelled)
|
|
51
|
-
console.warn("Terrain provider failed to load:", error);
|
|
52
|
-
}
|
|
48
|
+
if (!isCancelled) console.warn("Terrain provider failed to load:", error);
|
|
53
49
|
});
|
|
54
50
|
|
|
55
51
|
return () => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ArcGISTiledElevationTerrainProvider,
|
|
3
2
|
CesiumTerrainProvider,
|
|
4
3
|
EllipsoidTerrainProvider,
|
|
5
4
|
IonResource,
|
|
@@ -12,6 +11,8 @@ import { AssetsCesiumProperty } from "../../../../Map";
|
|
|
12
11
|
|
|
13
12
|
type TerrainType = NonNullable<TerrainProperty["type"]>;
|
|
14
13
|
|
|
14
|
+
const REEARTH_TERRAIN_URL = "https://terrain.reearth.land/cesium-mesh/ellipsoid";
|
|
15
|
+
|
|
15
16
|
type ProviderOpts = Pick<TerrainProperty, "normal"> &
|
|
16
17
|
AssetsCesiumProperty["terrain"] & {
|
|
17
18
|
terrain?: boolean;
|
|
@@ -20,13 +21,11 @@ type ProviderOpts = Pick<TerrainProperty, "normal"> &
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export default function useTerrainProviderPromise(opts: ProviderOpts) {
|
|
23
|
-
// Cache promises so we don’t recreate providers on every toggle
|
|
24
24
|
const cacheRef = useRef(new Map<string, Promise<TerrainProvider>>());
|
|
25
25
|
const ellipsoidRef = useRef<TerrainProvider>(undefined);
|
|
26
26
|
|
|
27
27
|
return useMemo<Promise<TerrainProvider>>(() => {
|
|
28
28
|
if (!opts.terrain) {
|
|
29
|
-
// single shared ellipsoid provider
|
|
30
29
|
if (!ellipsoidRef.current) ellipsoidRef.current = new EllipsoidTerrainProvider();
|
|
31
30
|
return Promise.resolve(ellipsoidRef.current);
|
|
32
31
|
}
|
|
@@ -43,31 +42,30 @@ export default function useTerrainProviderPromise(opts: ProviderOpts) {
|
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
function makeKey(type: TerrainType, opts: ProviderOpts) {
|
|
46
|
-
// Key should change when output provider would differ
|
|
47
45
|
const asset = opts.ionAsset ?? "";
|
|
48
46
|
const url = opts.ionUrl ?? "";
|
|
47
|
+
const ionToken = opts.ionAccessToken ?? "";
|
|
49
48
|
const normal = String(!!opts.normal);
|
|
50
|
-
return `${type}|asset:${asset}|url:${url}|normal:${normal}`;
|
|
49
|
+
return `${type}|asset:${asset}|url:${url}|ion:${ionToken}|normal:${normal}`;
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
function createProvider(type: TerrainType, opts: ProviderOpts): Promise<TerrainProvider> {
|
|
54
53
|
switch (type) {
|
|
55
|
-
case "
|
|
54
|
+
case "reearth_terrain":
|
|
55
|
+
return CesiumTerrainProvider.fromUrl(REEARTH_TERRAIN_URL, {
|
|
56
|
+
requestVertexNormals: !!opts.normal,
|
|
57
|
+
requestWaterMask: false,
|
|
58
|
+
}) as Promise<TerrainProvider>;
|
|
59
|
+
|
|
60
|
+
case "cesium": {
|
|
56
61
|
return CesiumTerrainProvider.fromUrl(
|
|
57
62
|
IonResource.fromAssetId(1, { accessToken: opts.ionAccessToken }),
|
|
58
63
|
{ requestVertexNormals: !!opts.normal, requestWaterMask: false },
|
|
59
64
|
) as Promise<TerrainProvider>;
|
|
65
|
+
}
|
|
60
66
|
|
|
61
|
-
case "
|
|
62
|
-
return
|
|
63
|
-
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
|
|
64
|
-
) as Promise<TerrainProvider>;
|
|
65
|
-
|
|
66
|
-
case "cesiumion":
|
|
67
|
-
if (!opts.ionAsset && !opts.ionUrl) {
|
|
68
|
-
// Fallback to ellipsoid when misconfigured
|
|
69
|
-
return Promise.resolve(new EllipsoidTerrainProvider());
|
|
70
|
-
}
|
|
67
|
+
case "cesiumion": {
|
|
68
|
+
if (!opts.ionAsset && !opts.ionUrl) return Promise.resolve(new EllipsoidTerrainProvider());
|
|
71
69
|
return CesiumTerrainProvider.fromUrl(
|
|
72
70
|
opts.ionUrl ??
|
|
73
71
|
IonResource.fromAssetId(parseInt(String(opts.ionAsset), 10), {
|
|
@@ -75,5 +73,9 @@ function createProvider(type: TerrainType, opts: ProviderOpts): Promise<TerrainP
|
|
|
75
73
|
}),
|
|
76
74
|
{ requestVertexNormals: !!opts.normal },
|
|
77
75
|
) as Promise<TerrainProvider>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
default:
|
|
79
|
+
return Promise.resolve(new EllipsoidTerrainProvider());
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -1,119 +1,154 @@
|
|
|
1
1
|
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import { UrlTemplateImageryProvider } from "cesium";
|
|
2
3
|
import { expect, test, vi } from "vitest";
|
|
3
4
|
|
|
5
|
+
import type { CustomProviderConfig } from "../../../Map/types/customProvider";
|
|
6
|
+
|
|
4
7
|
import { type Tile, useImageryProviders } from "./Imagery";
|
|
5
8
|
|
|
6
9
|
test("useImageryProviders", () => {
|
|
7
10
|
const provider = vi.fn(({ url }: { url?: string } = {}): any => ({ hoge: url }));
|
|
8
|
-
const
|
|
9
|
-
|
|
11
|
+
const osmProvider = vi.fn((): any => ({ osm: true }));
|
|
12
|
+
|
|
13
|
+
const presets = {
|
|
14
|
+
cesium_ion_default: provider,
|
|
15
|
+
open_street_map: osmProvider,
|
|
16
|
+
} as any;
|
|
17
|
+
|
|
10
18
|
const { result, rerender } = renderHook(
|
|
11
|
-
({
|
|
19
|
+
({
|
|
20
|
+
tiles,
|
|
21
|
+
cesiumIonAccessToken,
|
|
22
|
+
customProvider,
|
|
23
|
+
}: {
|
|
24
|
+
tiles: Tile[];
|
|
25
|
+
cesiumIonAccessToken?: string;
|
|
26
|
+
customProvider?: CustomProviderConfig;
|
|
27
|
+
}) =>
|
|
12
28
|
useImageryProviders({
|
|
13
29
|
tiles,
|
|
14
30
|
presets,
|
|
15
31
|
cesiumIonAccessToken,
|
|
32
|
+
customProvider,
|
|
16
33
|
}),
|
|
17
|
-
{
|
|
34
|
+
{
|
|
35
|
+
initialProps: {
|
|
36
|
+
tiles: [{ id: "1", type: "cesium_ion_default" }],
|
|
37
|
+
cesiumIonAccessToken: undefined,
|
|
38
|
+
customProvider: undefined,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
18
41
|
);
|
|
19
42
|
|
|
20
43
|
const typedRerender = rerender as (props: {
|
|
21
44
|
tiles: Tile[];
|
|
22
45
|
cesiumIonAccessToken?: string;
|
|
46
|
+
customProvider?: CustomProviderConfig;
|
|
23
47
|
}) => void;
|
|
24
48
|
|
|
25
|
-
expect(result.current.providers).toEqual({
|
|
49
|
+
expect(result.current.providers).toEqual({
|
|
50
|
+
"1": ["cesium_ion_default", undefined, undefined, { hoge: undefined }],
|
|
51
|
+
});
|
|
26
52
|
expect(result.current.updated).toBe(true);
|
|
27
53
|
expect(provider).toBeCalledTimes(1);
|
|
28
|
-
const prevImageryProvider = result.current.providers["1"][
|
|
54
|
+
const prevImageryProvider = result.current.providers["1"][3];
|
|
29
55
|
|
|
30
56
|
// re-render with same tiles
|
|
31
|
-
typedRerender({ tiles: [{ id: "1", type: "
|
|
57
|
+
typedRerender({ tiles: [{ id: "1", type: "cesium_ion_default" }] });
|
|
32
58
|
|
|
33
|
-
expect(result.current.providers).toEqual({
|
|
34
|
-
|
|
59
|
+
expect(result.current.providers).toEqual({
|
|
60
|
+
"1": ["cesium_ion_default", undefined, undefined, { hoge: undefined }],
|
|
61
|
+
});
|
|
62
|
+
expect(result.current.providers["1"][3]).toBe(prevImageryProvider); // 1's provider should be reused
|
|
35
63
|
expect(provider).toBeCalledTimes(1);
|
|
36
64
|
|
|
37
65
|
// update a tile URL
|
|
38
|
-
typedRerender({ tiles: [{ id: "1", type: "
|
|
66
|
+
typedRerender({ tiles: [{ id: "1", type: "cesium_ion_default", url: "a" }] });
|
|
39
67
|
|
|
40
|
-
expect(result.current.providers).toEqual({
|
|
41
|
-
|
|
68
|
+
expect(result.current.providers).toEqual({
|
|
69
|
+
"1": ["cesium_ion_default", "a", undefined, { hoge: "a" }],
|
|
70
|
+
});
|
|
71
|
+
expect(result.current.providers["1"][3]).not.toBe(prevImageryProvider);
|
|
42
72
|
expect(result.current.updated).toBe(true);
|
|
43
73
|
expect(provider).toBeCalledTimes(2);
|
|
44
74
|
expect(provider).toBeCalledWith({ url: "a" });
|
|
45
|
-
const prevImageryProvider2 = result.current.providers["1"][
|
|
75
|
+
const prevImageryProvider2 = result.current.providers["1"][3];
|
|
46
76
|
|
|
47
77
|
// add a tile with URL
|
|
48
78
|
typedRerender({
|
|
49
79
|
tiles: [
|
|
50
|
-
{ id: "2", type: "
|
|
51
|
-
{ id: "1", type: "
|
|
80
|
+
{ id: "2", type: "cesium_ion_default" },
|
|
81
|
+
{ id: "1", type: "cesium_ion_default", url: "a" },
|
|
52
82
|
],
|
|
53
83
|
});
|
|
54
84
|
|
|
55
85
|
expect(result.current.providers).toEqual({
|
|
56
|
-
"2": ["
|
|
57
|
-
"1": ["
|
|
86
|
+
"2": ["cesium_ion_default", undefined, undefined, { hoge: undefined }],
|
|
87
|
+
"1": ["cesium_ion_default", "a", undefined, { hoge: "a" }],
|
|
58
88
|
});
|
|
59
89
|
expect(result.current.updated).toBe(true);
|
|
60
|
-
expect(result.current.providers["1"][
|
|
90
|
+
expect(result.current.providers["1"][3]).toBe(prevImageryProvider2); // 1's provider should be reused
|
|
61
91
|
expect(provider).toBeCalledTimes(3);
|
|
62
92
|
|
|
63
93
|
// sort tiles
|
|
64
94
|
typedRerender({
|
|
65
95
|
tiles: [
|
|
66
|
-
{ id: "1", type: "
|
|
67
|
-
{ id: "2", type: "
|
|
96
|
+
{ id: "1", type: "cesium_ion_default", url: "a" },
|
|
97
|
+
{ id: "2", type: "cesium_ion_default" },
|
|
68
98
|
],
|
|
69
99
|
});
|
|
70
100
|
|
|
71
101
|
expect(result.current.providers).toEqual({
|
|
72
|
-
"1": ["
|
|
73
|
-
"2": ["
|
|
102
|
+
"1": ["cesium_ion_default", "a", undefined, { hoge: "a" }],
|
|
103
|
+
"2": ["cesium_ion_default", undefined, undefined, { hoge: undefined }],
|
|
74
104
|
});
|
|
75
105
|
expect(result.current.updated).toBe(true);
|
|
76
|
-
expect(result.current.providers["1"][
|
|
106
|
+
expect(result.current.providers["1"][3]).toBe(prevImageryProvider2); // 1's provider should be reused
|
|
77
107
|
expect(provider).toBeCalledTimes(3);
|
|
78
108
|
|
|
79
|
-
//
|
|
109
|
+
// Ion token update triggers provider recreation for cesium_ion_* types
|
|
80
110
|
typedRerender({
|
|
81
|
-
tiles: [{ id: "1", type: "
|
|
111
|
+
tiles: [{ id: "1", type: "cesium_ion_default", url: "a" }],
|
|
82
112
|
cesiumIonAccessToken: "a",
|
|
83
113
|
});
|
|
84
114
|
|
|
85
115
|
expect(result.current.providers).toEqual({
|
|
86
|
-
"1": ["
|
|
116
|
+
"1": ["cesium_ion_default", "a", undefined, { hoge: "a" }],
|
|
87
117
|
});
|
|
88
118
|
expect(result.current.updated).toBe(true);
|
|
89
|
-
expect(result.current.providers["1"][
|
|
119
|
+
expect(result.current.providers["1"][3]).not.toBe(prevImageryProvider2);
|
|
90
120
|
expect(provider).toBeCalledTimes(4);
|
|
91
121
|
|
|
92
|
-
//
|
|
122
|
+
// unknown type without customProvider: falls back directly to open_street_map
|
|
93
123
|
typedRerender({
|
|
94
|
-
tiles: [{ id: "1", type: "
|
|
95
|
-
cesiumIonAccessToken: "a",
|
|
124
|
+
tiles: [{ id: "1", type: "unexpected_type", url: "u" }],
|
|
96
125
|
});
|
|
97
126
|
|
|
98
|
-
expect(result.current.providers).
|
|
99
|
-
|
|
100
|
-
});
|
|
127
|
+
expect(result.current.providers["1"][0]).toBe("unexpected_type");
|
|
128
|
+
expect(result.current.providers["1"][3]).toEqual({ osm: true });
|
|
101
129
|
expect(result.current.updated).toBe(true);
|
|
102
|
-
expect(
|
|
103
|
-
expect(provider2).toBeCalledTimes(1);
|
|
130
|
+
expect(osmProvider).toBeCalledTimes(1);
|
|
104
131
|
|
|
105
|
-
//
|
|
132
|
+
// unknown type with a matching customProvider entry: uses UrlTemplateImageryProvider
|
|
106
133
|
typedRerender({
|
|
107
|
-
tiles: [{ id: "1", type: "
|
|
134
|
+
tiles: [{ id: "1", type: "my_custom_satellite", url: "u" }],
|
|
135
|
+
customProvider: {
|
|
136
|
+
imagery: {
|
|
137
|
+
providers: [
|
|
138
|
+
{
|
|
139
|
+
id: "my_custom_satellite",
|
|
140
|
+
url: "https://example.com/{z}/{x}/{y}.png",
|
|
141
|
+
credit: "© Example",
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
108
146
|
});
|
|
109
147
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
expect(result.current.updated).toBe(true);
|
|
115
|
-
expect(provider).toBeCalledTimes(5);
|
|
116
|
-
expect(provider2).toBeCalledTimes(1);
|
|
148
|
+
const dynamicProvider = result.current.providers["1"][3];
|
|
149
|
+
expect(dynamicProvider).toBeDefined();
|
|
150
|
+
expect(dynamicProvider).toBeInstanceOf(UrlTemplateImageryProvider);
|
|
151
|
+
expect(osmProvider).toBeCalledTimes(1); // osm not called again
|
|
117
152
|
|
|
118
153
|
typedRerender({ tiles: [] });
|
|
119
154
|
expect(result.current.providers).toEqual({});
|