@deck.gl/geo-layers 8.7.7 → 8.8.0-alpha.2

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 (48) hide show
  1. package/dist/dist.dev.js +62897 -30614
  2. package/dist/es5/index.js +8 -0
  3. package/dist/es5/index.js.map +1 -1
  4. package/dist/es5/mvt-layer/mvt-layer.js +9 -12
  5. package/dist/es5/mvt-layer/mvt-layer.js.map +1 -1
  6. package/dist/es5/tile-3d-layer/tile-3d-layer.js +13 -10
  7. package/dist/es5/tile-3d-layer/tile-3d-layer.js.map +1 -1
  8. package/dist/es5/tile-layer/tile-2d-header.js +36 -17
  9. package/dist/es5/tile-layer/tile-2d-header.js.map +1 -1
  10. package/dist/es5/tile-layer/tile-2d-traversal.js +13 -3
  11. package/dist/es5/tile-layer/tile-2d-traversal.js.map +1 -1
  12. package/dist/es5/tile-layer/tile-layer.js +18 -12
  13. package/dist/es5/tile-layer/tile-layer.js.map +1 -1
  14. package/dist/es5/tile-layer/tileset-2d.js +122 -96
  15. package/dist/es5/tile-layer/tileset-2d.js.map +1 -1
  16. package/dist/es5/tile-layer/types.js +2 -0
  17. package/dist/es5/tile-layer/types.js.map +1 -0
  18. package/dist/es5/tile-layer/utils.js +27 -9
  19. package/dist/es5/tile-layer/utils.js.map +1 -1
  20. package/dist/esm/index.js +1 -0
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/mvt-layer/mvt-layer.js +9 -13
  23. package/dist/esm/mvt-layer/mvt-layer.js.map +1 -1
  24. package/dist/esm/tile-3d-layer/tile-3d-layer.js +8 -7
  25. package/dist/esm/tile-3d-layer/tile-3d-layer.js.map +1 -1
  26. package/dist/esm/tile-layer/tile-2d-header.js +54 -18
  27. package/dist/esm/tile-layer/tile-2d-header.js.map +1 -1
  28. package/dist/esm/tile-layer/tile-2d-traversal.js +17 -3
  29. package/dist/esm/tile-layer/tile-2d-traversal.js.map +1 -1
  30. package/dist/esm/tile-layer/tile-layer.js +20 -13
  31. package/dist/esm/tile-layer/tile-layer.js.map +1 -1
  32. package/dist/esm/tile-layer/tileset-2d.js +88 -54
  33. package/dist/esm/tile-layer/tileset-2d.js.map +1 -1
  34. package/dist/esm/tile-layer/types.js +2 -0
  35. package/dist/esm/tile-layer/types.js.map +1 -0
  36. package/dist/esm/tile-layer/utils.js +26 -11
  37. package/dist/esm/tile-layer/utils.js.map +1 -1
  38. package/dist.min.js +2 -2
  39. package/package.json +11 -11
  40. package/src/index.ts +5 -0
  41. package/src/mvt-layer/mvt-layer.js +6 -6
  42. package/src/tile-3d-layer/tile-3d-layer.js +6 -5
  43. package/src/tile-layer/{tile-2d-header.js → tile-2d-header.ts} +50 -16
  44. package/src/tile-layer/{tile-2d-traversal.js → tile-2d-traversal.ts} +49 -12
  45. package/src/tile-layer/{tile-layer.js → tile-layer.ts} +147 -28
  46. package/src/tile-layer/{tileset-2d.js → tileset-2d.ts} +143 -66
  47. package/src/tile-layer/types.ts +17 -0
  48. package/src/tile-layer/{utils.js → utils.ts} +62 -25
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@deck.gl/geo-layers",
3
3
  "description": "deck.gl layers supporting geospatial use cases and GIS formats",
4
4
  "license": "MIT",
5
- "version": "8.7.7",
5
+ "version": "8.8.0-alpha.2",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -29,16 +29,16 @@
29
29
  "prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env.dev"
30
30
  },
31
31
  "dependencies": {
32
- "@loaders.gl/3d-tiles": "^3.1.5",
33
- "@loaders.gl/gis": "^3.1.5",
34
- "@loaders.gl/loader-utils": "^3.1.5",
35
- "@loaders.gl/mvt": "^3.1.5",
36
- "@loaders.gl/terrain": "^3.1.5",
37
- "@loaders.gl/tiles": "^3.1.5",
32
+ "@loaders.gl/3d-tiles": "^3.2.0-alpha.4",
33
+ "@loaders.gl/gis": "^3.2.0-alpha.4",
34
+ "@loaders.gl/loader-utils": "^3.2.0-alpha.4",
35
+ "@loaders.gl/mvt": "^3.2.0-alpha.4",
36
+ "@loaders.gl/terrain": "^3.2.0-alpha.4",
37
+ "@loaders.gl/tiles": "^3.2.0-alpha.4",
38
38
  "@luma.gl/experimental": "^8.5.10",
39
- "@math.gl/core": "^3.5.7",
40
- "@math.gl/culling": "^3.5.7",
41
- "@math.gl/web-mercator": "^3.5.7",
39
+ "@math.gl/core": "3.6.0-alpha.5",
40
+ "@math.gl/culling": "3.6.0-alpha.5",
41
+ "@math.gl/web-mercator": "3.6.0-alpha.5",
42
42
  "h3-js": "^3.6.0",
43
43
  "long": "^3.2.0"
44
44
  },
@@ -49,5 +49,5 @@
49
49
  "@deck.gl/mesh-layers": "^8.0.0",
50
50
  "@loaders.gl/core": "^3.0.0"
51
51
  },
52
- "gitHead": "5a7e586411cb538d3319e35f8e07d61c9a3efb6d"
52
+ "gitHead": "a52215449dff06fb683f5afd6399526353d11f35"
53
53
  }
package/src/index.ts CHANGED
@@ -31,3 +31,8 @@ export {default as TerrainLayer} from './terrain-layer/terrain-layer';
31
31
  export {default as MVTLayer} from './mvt-layer/mvt-layer';
32
32
 
33
33
  export {getURLFromTemplate as _getURLFromTemplate} from './tile-layer/utils';
34
+ export {default as _Tileset2D} from './tile-layer/tileset-2d';
35
+
36
+ // Types
37
+
38
+ export type {TileLayerProps} from './tile-layer/tile-layer';
@@ -116,14 +116,14 @@ export default class MVTLayer extends TileLayer {
116
116
  let loadOptions = this.getLoadOptions();
117
117
  const {binary} = this.state;
118
118
  const {fetch} = this.props;
119
- const {signal, x, y, z} = tile;
119
+ const {signal, index} = tile;
120
120
  loadOptions = {
121
121
  ...loadOptions,
122
122
  mimeType: 'application/x-protobuf',
123
123
  mvt: {
124
124
  ...loadOptions?.mvt,
125
125
  coordinates: this.context.viewport.resolution ? 'wgs84' : 'local',
126
- tileIndex: {x, y, z}
126
+ tileIndex: index
127
127
  // Local worker debug
128
128
  // workerUrl: `modules/mvt/dist/mvt-loader.worker.js`
129
129
  // Set worker to null to skip web workers
@@ -135,14 +135,14 @@ export default class MVTLayer extends TileLayer {
135
135
  }
136
136
 
137
137
  renderSubLayers(props) {
138
- const {tile} = props;
139
- const worldScale = Math.pow(2, tile.z);
138
+ const {x, y, z} = props.tile.index;
139
+ const worldScale = Math.pow(2, z);
140
140
 
141
141
  const xScale = WORLD_SIZE / worldScale;
142
142
  const yScale = -xScale;
143
143
 
144
- const xOffset = (WORLD_SIZE * tile.x) / worldScale;
145
- const yOffset = WORLD_SIZE * (1 - tile.y / worldScale);
144
+ const xOffset = (WORLD_SIZE * x) / worldScale;
145
+ const yOffset = WORLD_SIZE * (1 - y / worldScale);
146
146
 
147
147
  const modelMatrix = new Matrix4().scale([xScale, yScale, 1]);
148
148
 
@@ -167,11 +167,12 @@ export default class Tile3DLayer extends CompositeLayer {
167
167
  if (!timeline || !viewportsNumber || !tileset3d) {
168
168
  return;
169
169
  }
170
- const frameNumber = tileset3d.update(Object.values(viewports));
171
- const tilesetChanged = this.state.frameNumber !== frameNumber;
172
- if (tilesetChanged) {
173
- this.setState({frameNumber});
174
- }
170
+ tileset3d.selectTiles(Object.values(viewports)).then(frameNumber => {
171
+ const tilesetChanged = this.state.frameNumber !== frameNumber;
172
+ if (tilesetChanged) {
173
+ this.setState({frameNumber});
174
+ }
175
+ });
175
176
  }
176
177
 
177
178
  _getSubLayer(tileHeader, oldLayer) {
@@ -1,11 +1,38 @@
1
1
  /* eslint-env browser */
2
- import {log} from '@deck.gl/core';
3
-
2
+ import {Layer, log} from '@deck.gl/core';
3
+ import {RequestScheduler} from '@loaders.gl/loader-utils';
4
+ import {TileBoundingBox, TileIndex, TileLoadProps} from './types';
5
+
6
+ export type TileLoadDataProps = {
7
+ requestScheduler: RequestScheduler;
8
+ getData: (props: TileLoadProps) => Promise<any>;
9
+ onLoad: (tile: Tile2DHeader) => void;
10
+ onError: (error: any, tile: Tile2DHeader) => void;
11
+ };
4
12
  export default class Tile2DHeader {
5
- constructor({x, y, z}) {
6
- this.x = x;
7
- this.y = y;
8
- this.z = z;
13
+ index: TileIndex;
14
+ isVisible: boolean;
15
+ isSelected: boolean;
16
+ parent: Tile2DHeader | null;
17
+ children: Tile2DHeader[] | null;
18
+ content: any;
19
+ state?: number;
20
+ layers?: Layer[] | null;
21
+
22
+ id!: string; // assigned _always_ with result of `getTileId`
23
+ bbox!: TileBoundingBox; // assigned _always_ with result of `getTileMetadata`
24
+ zoom!: number; // assigned _always_ with result of `getTileZoom`
25
+ userData?: Record<string, any>; // _may be_ assigned with result of `getTileMetadata`
26
+
27
+ private _abortController: AbortController | null;
28
+ private _loader: Promise<void> | undefined;
29
+ private _loaderId: number;
30
+ private _isLoaded: boolean;
31
+ private _isCancelled: boolean;
32
+ private _needsReload: boolean;
33
+
34
+ constructor(index: TileIndex) {
35
+ this.index = index;
9
36
  this.isVisible = false;
10
37
  this.isSelected = false;
11
38
  this.parent = null;
@@ -13,6 +40,8 @@ export default class Tile2DHeader {
13
40
 
14
41
  this.content = null;
15
42
 
43
+ this._loader = undefined;
44
+ this._abortController = null;
16
45
  this._loaderId = 0;
17
46
  this._isLoaded = false;
18
47
  this._isCancelled = false;
@@ -20,7 +49,7 @@ export default class Tile2DHeader {
20
49
  }
21
50
 
22
51
  get data() {
23
- return this.isLoading ? this._loader.then(() => this.data) : this.content;
52
+ return this.isLoading && this._loader ? this._loader.then(() => this.data) : this.content;
24
53
  }
25
54
 
26
55
  get isLoaded() {
@@ -44,13 +73,19 @@ export default class Tile2DHeader {
44
73
  }
45
74
 
46
75
  /* eslint-disable max-statements */
47
- async _loadData({getData, requestScheduler, onLoad, onError}) {
48
- const {x, y, z, bbox} = this;
76
+ private async _loadData({
77
+ getData,
78
+ requestScheduler,
79
+ onLoad,
80
+ onError
81
+ }: TileLoadDataProps): Promise<void> {
82
+ const {index, id, bbox, userData, zoom} = this;
49
83
  const loaderId = this._loaderId;
50
84
 
51
- this._abortController = new AbortController(); // eslint-disable-line no-undef
85
+ this._abortController = new AbortController();
52
86
  const {signal} = this._abortController;
53
87
 
88
+ // @ts-expect-error (2345) Argument of type '(tile: any) => 1 | -1' is not assignable ...
54
89
  const requestToken = await requestScheduler.scheduleRequest(this, tile => {
55
90
  return tile.isSelected ? 1 : -1;
56
91
  });
@@ -68,7 +103,7 @@ export default class Tile2DHeader {
68
103
  let tileData = null;
69
104
  let error;
70
105
  try {
71
- tileData = await getData({x, y, z, bbox, signal});
106
+ tileData = await getData({index, id, bbox, userData, zoom, signal});
72
107
  } catch (err) {
73
108
  error = err || true;
74
109
  } finally {
@@ -99,9 +134,8 @@ export default class Tile2DHeader {
99
134
  onLoad(this);
100
135
  }
101
136
  }
102
- /* eslint-enable max-statements */
103
137
 
104
- loadData(opts) {
138
+ loadData(opts: TileLoadDataProps): Promise<void> {
105
139
  this._isLoaded = false;
106
140
  this._isCancelled = false;
107
141
  this._needsReload = false;
@@ -110,7 +144,7 @@ export default class Tile2DHeader {
110
144
  return this._loader;
111
145
  }
112
146
 
113
- setNeedsReload() {
147
+ setNeedsReload(): void {
114
148
  if (this.isLoading) {
115
149
  this.abort();
116
150
  this._loader = undefined;
@@ -118,12 +152,12 @@ export default class Tile2DHeader {
118
152
  this._needsReload = true;
119
153
  }
120
154
 
121
- abort() {
155
+ abort(): void {
122
156
  if (this.isLoaded) {
123
157
  return;
124
158
  }
125
159
 
126
160
  this._isCancelled = true;
127
- this._abortController.abort();
161
+ this._abortController?.abort();
128
162
  }
129
163
  }
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable complexity */
2
+ import {Viewport, WebMercatorViewport, _GlobeViewport} from '@deck.gl/core';
2
3
  import {
3
4
  CullingVolume,
4
5
  Plane,
@@ -6,6 +7,7 @@ import {
6
7
  makeOrientedBoundingBoxFromPoints
7
8
  } from '@math.gl/culling';
8
9
  import {lngLatToWorld} from '@math.gl/web-mercator';
10
+ import {Bounds, TileIndex, ZRange} from './types';
9
11
  import {osmTile2lngLat} from './utils';
10
12
 
11
13
  const TILE_SIZE = 512;
@@ -31,6 +33,15 @@ const REF_POINTS_11 = REF_POINTS_9.concat([
31
33
  ]); // 2 additional points on equator for top tile
32
34
 
33
35
  class OSMNode {
36
+ x: number;
37
+ y: number;
38
+ z: number;
39
+
40
+ private childVisible?: boolean;
41
+ private selected?: boolean;
42
+
43
+ private _children?: OSMNode[];
44
+
34
45
  constructor(x, y, z) {
35
46
  this.x = x;
36
47
  this.y = y;
@@ -52,7 +63,16 @@ class OSMNode {
52
63
  return this._children;
53
64
  }
54
65
 
55
- update(params) {
66
+ update(params: {
67
+ viewport: Viewport;
68
+ project: ((xyz: number[]) => number[]) | null;
69
+ cullingVolume: CullingVolume;
70
+ elevationBounds: ZRange;
71
+ minZ: number;
72
+ maxZ: number;
73
+ bounds?: Bounds;
74
+ offset: number;
75
+ }) {
56
76
  const {viewport, cullingVolume, elevationBounds, minZ, maxZ, bounds, offset, project} = params;
57
77
  const boundingVolume = this.getBoundingVolume(elevationBounds, offset, project);
58
78
 
@@ -92,7 +112,7 @@ class OSMNode {
92
112
  return true;
93
113
  }
94
114
 
95
- getSelected(result = []) {
115
+ getSelected(result: OSMNode[] = []): OSMNode[] {
96
116
  if (this.selected) {
97
117
  result.push(this);
98
118
  }
@@ -104,7 +124,7 @@ class OSMNode {
104
124
  return result;
105
125
  }
106
126
 
107
- insideBounds([minX, minY, maxX, maxY]) {
127
+ insideBounds([minX, minY, maxX, maxY]: Bounds): boolean {
108
128
  const scale = Math.pow(2, this.z);
109
129
  const extent = TILE_SIZE / scale;
110
130
 
@@ -116,7 +136,11 @@ class OSMNode {
116
136
  );
117
137
  }
118
138
 
119
- getBoundingVolume(zRange, worldOffset, project) {
139
+ getBoundingVolume(
140
+ zRange: ZRange,
141
+ worldOffset: number,
142
+ project: ((xyz: number[]) => number[]) | null
143
+ ) {
120
144
  if (project) {
121
145
  // Custom projection
122
146
  // Estimate bounding box from sample points
@@ -124,9 +148,9 @@ class OSMNode {
124
148
  const refPoints = this.z < 1 ? REF_POINTS_11 : this.z < 2 ? REF_POINTS_9 : REF_POINTS_5;
125
149
 
126
150
  // Convert from tile-relative coordinates to common space
127
- const refPointPositions = [];
151
+ const refPointPositions: number[][] = [];
128
152
  for (const p of refPoints) {
129
- const lngLat = osmTile2lngLat(this.x + p[0], this.y + p[1], this.z);
153
+ const lngLat: number[] = osmTile2lngLat(this.x + p[0], this.y + p[1], this.z);
130
154
  lngLat[2] = zRange[0];
131
155
  refPointPositions.push(project(lngLat));
132
156
 
@@ -154,11 +178,20 @@ class OSMNode {
154
178
  }
155
179
  }
156
180
 
157
- export function getOSMTileIndices(viewport, maxZ, zRange, bounds) {
158
- const project = viewport.resolution ? viewport.projectPosition : null;
181
+ export function getOSMTileIndices(
182
+ viewport: Viewport,
183
+ maxZ: number,
184
+ zRange: ZRange | undefined,
185
+ bounds?: Bounds
186
+ ): TileIndex[] {
187
+ const project: ((xyz: number[]) => number[]) | null =
188
+ viewport instanceof _GlobeViewport && viewport.resolution
189
+ ? // eslint-disable-next-line @typescript-eslint/unbound-method
190
+ viewport.projectPosition
191
+ : null;
159
192
 
160
193
  // Get the culling volume of the current camera
161
- const planes = Object.values(viewport.getFrustumPlanes()).map(
194
+ const planes: Plane[] = Object.values(viewport.getFrustumPlanes()).map(
162
195
  ({normal, distance}) => new Plane(normal.clone().negate(), distance)
163
196
  );
164
197
  const cullingVolume = new CullingVolume(planes);
@@ -169,7 +202,7 @@ export function getOSMTileIndices(viewport, maxZ, zRange, bounds) {
169
202
  const elevationMax = (zRange && zRange[1] * unitsPerMeter) || 0;
170
203
 
171
204
  // Always load at the current zoom level if pitch is small
172
- const minZ = viewport.pitch <= 60 ? maxZ : 0;
205
+ const minZ = viewport instanceof WebMercatorViewport && viewport.pitch <= 60 ? maxZ : 0;
173
206
 
174
207
  // Map extent to OSM position
175
208
  if (bounds) {
@@ -184,7 +217,7 @@ export function getOSMTileIndices(viewport, maxZ, zRange, bounds) {
184
217
  viewport,
185
218
  project,
186
219
  cullingVolume,
187
- elevationBounds: [elevationMin, elevationMax],
220
+ elevationBounds: [elevationMin, elevationMax] as ZRange,
188
221
  minZ,
189
222
  maxZ,
190
223
  bounds,
@@ -194,7 +227,11 @@ export function getOSMTileIndices(viewport, maxZ, zRange, bounds) {
194
227
 
195
228
  root.update(traversalParams);
196
229
 
197
- if (viewport.subViewports && viewport.subViewports.length > 1) {
230
+ if (
231
+ viewport instanceof WebMercatorViewport &&
232
+ viewport.subViewports &&
233
+ viewport.subViewports.length > 1
234
+ ) {
198
235
  // Check worlds in repeated maps
199
236
  traversalParams.offset = -1;
200
237
  while (root.update(traversalParams)) {
@@ -1,10 +1,22 @@
1
- import {CompositeLayer, _flatten as flatten} from '@deck.gl/core';
1
+ import {
2
+ assert,
3
+ ChangeFlags,
4
+ CompositeLayer,
5
+ CompositeLayerProps,
6
+ Layer,
7
+ LayerProps,
8
+ _flatten as flatten
9
+ } from '@deck.gl/core';
2
10
  import {GeoJsonLayer} from '@deck.gl/layers';
11
+ import {LayersList} from 'modules/core/src/lib/layer-manager';
12
+ import Tile2DHeader from './tile-2d-header';
3
13
 
4
- import Tileset2D, {STRATEGY_DEFAULT} from './tileset-2d';
14
+ import Tileset2D, {RefinementStrategy, STRATEGY_DEFAULT, Tileset2DProps} from './tileset-2d';
15
+ import {TileLoadProps, ZRange} from './types';
5
16
  import {urlType, getURLFromTemplate} from './utils';
6
17
 
7
18
  const defaultProps = {
19
+ TilesetClass: Tileset2D,
8
20
  data: [],
9
21
  dataComparator: urlType.equals,
10
22
  renderSubLayers: {type: 'function', value: props => new GeoJsonLayer(props), compare: false},
@@ -27,7 +39,96 @@ const defaultProps = {
27
39
  zoomOffset: 0
28
40
  };
29
41
 
30
- export default class TileLayer extends CompositeLayer {
42
+ export type TileLayerProps<DataT = any> = CompositeLayerProps<DataT> & {
43
+ /**
44
+ * Renders one or an array of Layer instances.
45
+ */
46
+ renderSubLayers: (
47
+ props: TileLayerProps & {
48
+ id: string;
49
+ data: any;
50
+ _offset: number;
51
+ tile: Tile2DHeader;
52
+ }
53
+ ) => LayersList;
54
+ /**
55
+ * If supplied, `getTileData` is called to retrieve the data of each tile.
56
+ */
57
+ getTileData: (props: TileLoadProps) => Promise<any> | any;
58
+
59
+ /** Called when all tiles in the current viewport are loaded. */
60
+ onViewportLoad?: (tiles: Tile2DHeader[]) => void;
61
+
62
+ /** Called when a tile successfully loads. */
63
+ onTileLoad: (tile: Tile2DHeader) => void;
64
+
65
+ /** Called when a tile is cleared from cache. */
66
+ onTileUnload: (tile: Tile2DHeader) => void;
67
+
68
+ /** Called when a tile failed to load. */
69
+ onTileError: (err: any) => void;
70
+
71
+ /** The bounding box of the layer's data. */
72
+ extent: number[] | undefined | null;
73
+
74
+ /** The pixel dimension of the tiles, usually a power of 2. */
75
+ tileSize: number;
76
+
77
+ /** The max zoom level of the layer's data. */
78
+ maxZoom: number;
79
+
80
+ /** The min zoom level of the layer's data. */
81
+ minZoom: number;
82
+
83
+ /** The maximum number of tiles that can be cached. */
84
+ maxCacheSize: number | undefined | null;
85
+
86
+ /**
87
+ * The maximum memory used for caching tiles.
88
+ *
89
+ * @default null
90
+ */
91
+ maxCacheByteSize: number | undefined;
92
+
93
+ /**
94
+ * How the tile layer refines the visibility of tiles.
95
+ *
96
+ * @default 'best-available'
97
+ */
98
+ refinementStrategy: RefinementStrategy;
99
+
100
+ /** Range of minimum and maximum heights in the tile. */
101
+ zRange: ZRange | null;
102
+
103
+ /**
104
+ * The maximum number of concurrent getTileData calls.
105
+ *
106
+ * @default 6
107
+ */
108
+ maxRequests: number;
109
+
110
+ /**
111
+ * This offset changes the zoom level at which the tiles are fetched.
112
+ *
113
+ * Needs to be an integer.
114
+ *
115
+ * @default 0
116
+ */
117
+ zoomOffset: number;
118
+ };
119
+
120
+ /**
121
+ * The TileLayer is a composite layer that makes it possible to visualize very large datasets.
122
+ *
123
+ * Instead of fetching the entire dataset, it only loads and renders what's visible in the current viewport.
124
+ */
125
+ export default class TileLayer<
126
+ DataT = any,
127
+ PropsT extends TileLayerProps<DataT> = TileLayerProps<DataT>
128
+ > extends CompositeLayer<PropsT> {
129
+ static defaultProps = defaultProps as any;
130
+ static layerName = 'TileLayer';
131
+
31
132
  initializeState() {
32
133
  this.state = {
33
134
  tileset: null,
@@ -36,21 +137,30 @@ export default class TileLayer extends CompositeLayer {
36
137
  }
37
138
 
38
139
  finalizeState() {
39
- this.state.tileset?.finalize();
140
+ this.state?.tileset?.finalize();
40
141
  }
41
142
 
42
- get isLoaded() {
43
- const {tileset} = this.state;
44
- return tileset.selectedTiles.every(
143
+ get isLoaded(): boolean {
144
+ return this.state?.tileset?.selectedTiles.every(
45
145
  tile => tile.isLoaded && tile.layers && tile.layers.every(layer => layer.isLoaded)
46
146
  );
47
147
  }
48
148
 
49
- shouldUpdateState({changeFlags}) {
149
+ shouldUpdateState({changeFlags}): boolean {
50
150
  return changeFlags.somethingChanged;
51
151
  }
52
152
 
53
- updateState({props, changeFlags}) {
153
+ updateState({
154
+ props,
155
+ changeFlags
156
+ }: {
157
+ props: TileLayerProps;
158
+ oldProps: TileLayerProps;
159
+ context: any;
160
+ changeFlags: ChangeFlags;
161
+ }) {
162
+ assert(this.state);
163
+
54
164
  let {tileset} = this.state;
55
165
  const propsChanged = changeFlags.propsOrDataChanged || changeFlags.updateTriggersChanged;
56
166
  const dataChanged =
@@ -59,7 +169,7 @@ export default class TileLayer extends CompositeLayer {
59
169
  (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getTileData));
60
170
 
61
171
  if (!tileset) {
62
- tileset = new Tileset2D(this._getTilesetOptions(props));
172
+ tileset = new this.props.TilesetClass(this._getTilesetOptions(props));
63
173
  this.setState({tileset});
64
174
  } else if (propsChanged) {
65
175
  tileset.setOptions(this._getTilesetOptions(props));
@@ -79,7 +189,7 @@ export default class TileLayer extends CompositeLayer {
79
189
  this._updateTileset();
80
190
  }
81
191
 
82
- _getTilesetOptions(props) {
192
+ _getTilesetOptions(props: TileLayerProps): Tileset2DProps {
83
193
  const {
84
194
  tileSize,
85
195
  maxCacheSize,
@@ -110,7 +220,8 @@ export default class TileLayer extends CompositeLayer {
110
220
  };
111
221
  }
112
222
 
113
- _updateTileset() {
223
+ _updateTileset(): void {
224
+ assert(this.state && this.context);
114
225
  const {tileset} = this.state;
115
226
  const {zRange, modelMatrix} = this.props;
116
227
  const frameNumber = tileset.update(this.context.viewport, {zRange, modelMatrix});
@@ -131,7 +242,9 @@ export default class TileLayer extends CompositeLayer {
131
242
  this.state.isLoaded = isLoaded;
132
243
  }
133
244
 
134
- _onViewportLoad() {
245
+ _onViewportLoad(): void {
246
+ assert(this.state);
247
+
135
248
  const {tileset} = this.state;
136
249
  const {onViewportLoad} = this.props;
137
250
 
@@ -140,46 +253,54 @@ export default class TileLayer extends CompositeLayer {
140
253
  }
141
254
  }
142
255
 
143
- _onTileLoad(tile) {
256
+ _onTileLoad(tile: Tile2DHeader): void {
144
257
  this.props.onTileLoad(tile);
145
258
  tile.layers = null;
146
259
 
147
260
  this.setNeedsUpdate();
148
261
  }
149
262
 
150
- _onTileError(error, tile) {
263
+ _onTileError(error: any, tile: Tile2DHeader) {
151
264
  this.props.onTileError(error);
152
265
  tile.layers = null;
153
266
 
154
267
  this.setNeedsUpdate();
155
268
  }
156
269
 
157
- _onTileUnload(tile) {
270
+ _onTileUnload(tile: Tile2DHeader) {
158
271
  this.props.onTileUnload(tile);
159
272
  }
160
273
 
161
274
  // Methods for subclass to override
162
275
 
163
- getTileData(tile) {
276
+ getTileData(tile: TileLoadProps) {
164
277
  const {data, getTileData, fetch} = this.props;
165
278
  const {signal} = tile;
166
279
 
167
- tile.url = getURLFromTemplate(data, tile);
280
+ tile.url =
281
+ typeof data === 'string' || Array.isArray(data) ? getURLFromTemplate(data, tile) : null;
168
282
 
169
283
  if (getTileData) {
170
284
  return getTileData(tile);
171
285
  }
172
- if (tile.url) {
286
+ if (fetch && tile.url) {
173
287
  return fetch(tile.url, {propName: 'data', layer: this, signal});
174
288
  }
175
289
  return null;
176
290
  }
177
291
 
178
- renderSubLayers(props) {
292
+ renderSubLayers(
293
+ props: TileLayerProps & {
294
+ id: string;
295
+ data: any;
296
+ _offset: number;
297
+ tile: Tile2DHeader;
298
+ }
299
+ ): LayersList {
179
300
  return this.props.renderSubLayers(props);
180
301
  }
181
302
 
182
- getSubLayerPropsByTile(tile) {
303
+ getSubLayerPropsByTile(tile: Tile2DHeader): LayerProps | null {
183
304
  return null;
184
305
  }
185
306
 
@@ -194,8 +315,9 @@ export default class TileLayer extends CompositeLayer {
194
315
  }
195
316
  }
196
317
 
197
- renderLayers() {
198
- return this.state.tileset.tiles.map(tile => {
318
+ renderLayers(): Layer[] {
319
+ assert(this.state);
320
+ return this.state.tileset.tiles.map((tile: Tile2DHeader) => {
199
321
  const subLayerProps = this.getSubLayerPropsByTile(tile);
200
322
  // cache the rendered layer in the tile
201
323
  if (!tile.isLoaded && !tile.content) {
@@ -203,7 +325,7 @@ export default class TileLayer extends CompositeLayer {
203
325
  } else if (!tile.layers) {
204
326
  const layers = this.renderSubLayers({
205
327
  ...this.props,
206
- id: `${this.id}-${tile.x}-${tile.y}-${tile.z}`,
328
+ id: `${this.id}-${tile.id}`,
207
329
  data: tile.content,
208
330
  _offset: 0,
209
331
  tile
@@ -218,7 +340,7 @@ export default class TileLayer extends CompositeLayer {
218
340
  subLayerProps &&
219
341
  tile.layers[0] &&
220
342
  Object.keys(subLayerProps).some(
221
- propName => tile.layers[0].props[propName] !== subLayerProps[propName]
343
+ propName => tile.layers![0].props[propName] !== subLayerProps[propName]
222
344
  )
223
345
  ) {
224
346
  tile.layers = tile.layers.map(layer => layer.clone(subLayerProps));
@@ -231,6 +353,3 @@ export default class TileLayer extends CompositeLayer {
231
353
  return layer.props.tile.isVisible;
232
354
  }
233
355
  }
234
-
235
- TileLayer.layerName = 'TileLayer';
236
- TileLayer.defaultProps = defaultProps;