@deck.gl/geo-layers 8.7.9 → 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.
- package/dist/dist.dev.js +62897 -30614
- package/dist/es5/index.js +8 -0
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/mvt-layer/mvt-layer.js +9 -12
- package/dist/es5/mvt-layer/mvt-layer.js.map +1 -1
- package/dist/es5/tile-3d-layer/tile-3d-layer.js +13 -10
- package/dist/es5/tile-3d-layer/tile-3d-layer.js.map +1 -1
- package/dist/es5/tile-layer/tile-2d-header.js +36 -17
- package/dist/es5/tile-layer/tile-2d-header.js.map +1 -1
- package/dist/es5/tile-layer/tile-2d-traversal.js +13 -3
- package/dist/es5/tile-layer/tile-2d-traversal.js.map +1 -1
- package/dist/es5/tile-layer/tile-layer.js +18 -12
- package/dist/es5/tile-layer/tile-layer.js.map +1 -1
- package/dist/es5/tile-layer/tileset-2d.js +122 -96
- package/dist/es5/tile-layer/tileset-2d.js.map +1 -1
- package/dist/es5/tile-layer/types.js +2 -0
- package/dist/es5/tile-layer/types.js.map +1 -0
- package/dist/es5/tile-layer/utils.js +27 -9
- package/dist/es5/tile-layer/utils.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mvt-layer/mvt-layer.js +9 -13
- package/dist/esm/mvt-layer/mvt-layer.js.map +1 -1
- package/dist/esm/tile-3d-layer/tile-3d-layer.js +8 -7
- package/dist/esm/tile-3d-layer/tile-3d-layer.js.map +1 -1
- package/dist/esm/tile-layer/tile-2d-header.js +54 -18
- package/dist/esm/tile-layer/tile-2d-header.js.map +1 -1
- package/dist/esm/tile-layer/tile-2d-traversal.js +17 -3
- package/dist/esm/tile-layer/tile-2d-traversal.js.map +1 -1
- package/dist/esm/tile-layer/tile-layer.js +20 -13
- package/dist/esm/tile-layer/tile-layer.js.map +1 -1
- package/dist/esm/tile-layer/tileset-2d.js +88 -54
- package/dist/esm/tile-layer/tileset-2d.js.map +1 -1
- package/dist/esm/tile-layer/types.js +2 -0
- package/dist/esm/tile-layer/types.js.map +1 -0
- package/dist/esm/tile-layer/utils.js +26 -11
- package/dist/esm/tile-layer/utils.js.map +1 -1
- package/dist.min.js +2 -2
- package/package.json +11 -11
- package/src/index.ts +5 -0
- package/src/mvt-layer/mvt-layer.js +6 -6
- package/src/tile-3d-layer/tile-3d-layer.js +6 -5
- package/src/tile-layer/{tile-2d-header.js → tile-2d-header.ts} +50 -16
- package/src/tile-layer/{tile-2d-traversal.js → tile-2d-traversal.ts} +49 -12
- package/src/tile-layer/{tile-layer.js → tile-layer.ts} +147 -28
- package/src/tile-layer/{tileset-2d.js → tileset-2d.ts} +143 -66
- package/src/tile-layer/types.ts +17 -0
- 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.
|
|
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.
|
|
33
|
-
"@loaders.gl/gis": "^3.
|
|
34
|
-
"@loaders.gl/loader-utils": "^3.
|
|
35
|
-
"@loaders.gl/mvt": "^3.
|
|
36
|
-
"@loaders.gl/terrain": "^3.
|
|
37
|
-
"@loaders.gl/tiles": "^3.
|
|
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": "
|
|
40
|
-
"@math.gl/culling": "
|
|
41
|
-
"@math.gl/web-mercator": "
|
|
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": "
|
|
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,
|
|
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:
|
|
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 {
|
|
139
|
-
const worldScale = Math.pow(2,
|
|
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 *
|
|
145
|
-
const yOffset = WORLD_SIZE * (1 -
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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({
|
|
48
|
-
|
|
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();
|
|
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({
|
|
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
|
|
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(
|
|
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(
|
|
158
|
-
|
|
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 (
|
|
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 {
|
|
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
|
|
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
|
|
140
|
+
this.state?.tileset?.finalize();
|
|
40
141
|
}
|
|
41
142
|
|
|
42
|
-
get isLoaded() {
|
|
43
|
-
|
|
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({
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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;
|