Skip to content

Commit b2becc9

Browse files
authored
fix: handle unexpected preset tile type (#93)
1 parent 94a39a5 commit b2becc9

4 files changed

Lines changed: 60 additions & 25 deletions

File tree

example/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const TILES = [
2222
"esri_world_topo",
2323
"black_marble",
2424
"japan_gsi_standard",
25+
"test_unexpected_type",
2526
];
2627

2728
export const SKETCH_TOOLS: SketchType[] = [

src/engines/Cesium/core/Imagery.test.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,36 @@ import { type Tile, useImageryProviders } from "./Imagery";
66
test("useImageryProviders", () => {
77
const provider = vi.fn(({ url }: { url?: string } = {}): any => ({ hoge: url }));
88
const provider2 = vi.fn(({ url }: { url?: string } = {}): any => ({ hoge2: url }));
9-
const presets = { default: provider, foobar: provider2 };
9+
const presets = { default: provider, default_label: provider2 };
1010
const { result, rerender } = renderHook(
1111
({ tiles, cesiumIonAccessToken }: { tiles: Tile[]; cesiumIonAccessToken?: string }) =>
1212
useImageryProviders({
1313
tiles,
1414
presets,
1515
cesiumIonAccessToken,
1616
}),
17-
{ initialProps: { tiles: [{ id: "1", type: "default" }] } },
17+
{ initialProps: { tiles: [{ id: "1", type: "default" }], cesiumIonAccessToken: undefined } },
1818
);
1919

20+
const typedRerender = rerender as (props: {
21+
tiles: Tile[];
22+
cesiumIonAccessToken?: string;
23+
}) => void;
24+
2025
expect(result.current.providers).toEqual({ "1": ["default", undefined, { hoge: undefined }] });
2126
expect(result.current.updated).toBe(true);
2227
expect(provider).toBeCalledTimes(1);
2328
const prevImageryProvider = result.current.providers["1"][2];
2429

2530
// re-render with same tiles
26-
rerender({ tiles: [{ id: "1", type: "default" }] });
31+
typedRerender({ tiles: [{ id: "1", type: "default" }] });
2732

2833
expect(result.current.providers).toEqual({ "1": ["default", undefined, { hoge: undefined }] });
2934
expect(result.current.providers["1"][2]).toBe(prevImageryProvider); // 1's provider should be reused
3035
expect(provider).toBeCalledTimes(1);
3136

3237
// update a tile URL
33-
rerender({ tiles: [{ id: "1", type: "default", url: "a" }] });
38+
typedRerender({ tiles: [{ id: "1", type: "default", url: "a" }] });
3439

3540
expect(result.current.providers).toEqual({ "1": ["default", "a", { hoge: "a" }] });
3641
expect(result.current.providers["1"][2]).not.toBe(prevImageryProvider);
@@ -40,7 +45,7 @@ test("useImageryProviders", () => {
4045
const prevImageryProvider2 = result.current.providers["1"][2];
4146

4247
// add a tile with URL
43-
rerender({
48+
typedRerender({
4449
tiles: [
4550
{ id: "2", type: "default" },
4651
{ id: "1", type: "default", url: "a" },
@@ -56,7 +61,7 @@ test("useImageryProviders", () => {
5661
expect(provider).toBeCalledTimes(3);
5762

5863
// sort tiles
59-
rerender({
64+
typedRerender({
6065
tiles: [
6166
{ id: "1", type: "default", url: "a" },
6267
{ id: "2", type: "default" },
@@ -72,7 +77,7 @@ test("useImageryProviders", () => {
7277
expect(provider).toBeCalledTimes(3);
7378

7479
// delete a tile
75-
rerender({
80+
typedRerender({
7681
tiles: [{ id: "1", type: "default", url: "a" }],
7782
cesiumIonAccessToken: "a",
7883
});
@@ -85,18 +90,31 @@ test("useImageryProviders", () => {
8590
expect(provider).toBeCalledTimes(4);
8691

8792
// update a tile type
88-
rerender({
89-
tiles: [{ id: "1", type: "foobar", url: "u" }],
93+
typedRerender({
94+
tiles: [{ id: "1", type: "default_label", url: "u" }],
9095
cesiumIonAccessToken: "a",
9196
});
9297

9398
expect(result.current.providers).toEqual({
94-
"1": ["foobar", "u", { hoge2: "u" }],
99+
"1": ["default_label", "u", { hoge2: "u" }],
95100
});
96101
expect(result.current.updated).toBe(true);
97102
expect(provider).toBeCalledTimes(4);
98103
expect(provider2).toBeCalledTimes(1);
99104

100-
rerender({ tiles: [] });
105+
// update a tile type to unexpected type
106+
typedRerender({
107+
tiles: [{ id: "1", type: "unexpected_type", url: "u" }],
108+
});
109+
110+
expect(result.current.providers).toEqual({
111+
// unexpected type is treated as "default"
112+
"1": ["unexpected_type", "u", { hoge: "u" }],
113+
});
114+
expect(result.current.updated).toBe(true);
115+
expect(provider).toBeCalledTimes(5);
116+
expect(provider2).toBeCalledTimes(1);
117+
118+
typedRerender({ tiles: [] });
101119
expect(result.current.providers).toEqual({});
102120
});

src/engines/Cesium/core/Imagery.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { isEqual } from "lodash-es";
88
import { useCallback, useMemo, useRef, useLayoutEffect, useState, useEffect } from "react";
99
import { ImageryLayer } from "resium";
1010

11-
import { tiles as tilePresets } from "./presets";
11+
import { isValidPresetTileType, PresetTileType, tiles as tilePresets } from "./presets";
1212

1313
export type ImageryLayerData = {
1414
id: string;
@@ -90,7 +90,7 @@ export function useImageryProviders({
9090
tiles?: Tile[];
9191
cesiumIonAccessToken?: string;
9292
presets: {
93-
[key: string]: (opts?: {
93+
[K in PresetTileType]: (opts?: {
9494
url?: string;
9595
cesiumIonAccessToken?: string;
9696
heatmap?: boolean;
@@ -100,7 +100,7 @@ export function useImageryProviders({
100100
}): { providers: Providers; updated: boolean } {
101101
const newTile = useCallback(
102102
(t: Tile, ciat?: string) =>
103-
presets[t.type || "default"]({
103+
presets[isValidPresetTileType(t.type) ? t.type : "default"]({
104104
url: t.url,
105105
cesiumIonAccessToken: ciat,
106106
heatmap: t.heatmap,
@@ -113,11 +113,14 @@ export function useImageryProviders({
113113
const tileKeys = tiles.map(t => t.id).join(",");
114114
const prevTileKeys = useRef(tileKeys);
115115
const prevProviders = useRef<Providers>({});
116-
const zoomLevels = useMemo(() => tiles.map(t => {
117-
if (t.id && t.zoomLevel) return { [t.id]: t.zoomLevel };
118-
return
119-
}),
120-
[tiles]);
116+
const zoomLevels = useMemo(
117+
() =>
118+
tiles.map(t => {
119+
if (t.id && t.zoomLevel) return { [t.id]: t.zoomLevel };
120+
return;
121+
}),
122+
[tiles],
123+
);
121124
const prevZoomLevels = useRef(zoomLevels);
122125

123126
// Manage TileProviders so that TileProvider does not need to be recreated each time tiles are updated.

src/engines/Cesium/core/presets.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ import {
1010

1111
import { JapanGSIOptimalBVmapLabelImageryProvider } from "./labels/JapanGSIOptimalBVmapVectorMapLabel/JapanGSIOptimalBVmapLabelImageryProvider";
1212

13+
const PRESET_TILE_TYPES = [
14+
"default",
15+
"default_label",
16+
"default_road",
17+
"open_street_map",
18+
"black_marble",
19+
"japan_gsi_standard",
20+
"url",
21+
];
22+
23+
export type PresetTileType = (typeof PRESET_TILE_TYPES)[number];
24+
25+
export const isValidPresetTileType = (type: string | undefined): type is PresetTileType => {
26+
return PRESET_TILE_TYPES.includes(type as PresetTileType);
27+
};
28+
1329
export const tiles = {
1430
default: ({ cesiumIonAccessToken } = {}) =>
1531
IonImageryProvider.fromAssetId(IonWorldImageryStyle.AERIAL, {
@@ -26,8 +42,7 @@ export const tiles = {
2642
open_street_map: () =>
2743
new OpenStreetMapImageryProvider({
2844
url: "https://tile.openstreetmap.org",
29-
credit:
30-
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
45+
credit: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
3146
}),
3247
black_marble: ({ cesiumIonAccessToken } = {}) =>
3348
IonImageryProvider.fromAssetId(3812, {
@@ -43,15 +58,13 @@ export const tiles = {
4358
url
4459
? new UrlTemplateImageryProvider({
4560
url,
46-
tileDiscardPolicy: heatmap
47-
? new DiscardEmptyTileImagePolicy()
48-
: undefined,
61+
tileDiscardPolicy: heatmap ? new DiscardEmptyTileImagePolicy() : undefined,
4962
minimumLevel: tile_zoomLevel?.[0],
5063
maximumLevel: tile_zoomLevel?.[1],
5164
})
5265
: null,
5366
} as {
54-
[key: string]: (opts?: {
67+
[K in PresetTileType]: (opts?: {
5568
url?: string;
5669
cesiumIonAccessToken?: string;
5770
heatmap?: boolean;

0 commit comments

Comments
 (0)