@deck.gl-community/geo-layers 9.2.8 → 9.3.0-beta.1
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/global-grid-layer/global-grid-cluster-layer.d.ts.map +1 -1
- package/dist/global-grid-layer/global-grid-cluster-layer.js +1 -0
- package/dist/global-grid-layer/global-grid-cluster-layer.js.map +1 -1
- package/dist/index.cjs +1799 -7
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/shared-tile-2d-layer/deck-tile-traversal.d.ts +5 -0
- package/dist/shared-tile-2d-layer/deck-tile-traversal.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/deck-tile-traversal.js +173 -0
- package/dist/shared-tile-2d-layer/deck-tile-traversal.js.map +1 -0
- package/dist/shared-tile-2d-layer/deck-tileset-adapter.d.ts +26 -0
- package/dist/shared-tile-2d-layer/deck-tileset-adapter.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/deck-tileset-adapter.js +174 -0
- package/dist/shared-tile-2d-layer/deck-tileset-adapter.js.map +1 -0
- package/dist/shared-tile-2d-layer/index.d.ts +4 -0
- package/dist/shared-tile-2d-layer/index.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/index.js +6 -0
- package/dist/shared-tile-2d-layer/index.js.map +1 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-layer.d.ts +151 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-layer.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-layer.js +422 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-layer.js.map +1 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-view.d.ts +57 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-view.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-view.js +253 -0
- package/dist/shared-tile-2d-layer/shared-tile-2d-view.js.map +1 -0
- package/dist/shared-tile-2d-layer/url-template.d.ts +9 -0
- package/dist/shared-tile-2d-layer/url-template.d.ts.map +1 -0
- package/dist/shared-tile-2d-layer/url-template.js +25 -0
- package/dist/shared-tile-2d-layer/url-template.js.map +1 -0
- package/dist/tile-grid-layer/tile-grid-layer.d.ts +47 -0
- package/dist/tile-grid-layer/tile-grid-layer.d.ts.map +1 -0
- package/dist/tile-grid-layer/tile-grid-layer.js +94 -0
- package/dist/tile-grid-layer/tile-grid-layer.js.map +1 -0
- package/dist/tile-source-layer/tile-source-layer.d.ts +2 -2
- package/dist/tile-source-layer/tile-source-layer.d.ts.map +1 -1
- package/dist/tileset/adapter.d.ts +38 -0
- package/dist/tileset/adapter.d.ts.map +1 -0
- package/dist/tileset/adapter.js +5 -0
- package/dist/tileset/adapter.js.map +1 -0
- package/dist/tileset/index.cjs +721 -0
- package/dist/tileset/index.cjs.map +7 -0
- package/dist/tileset/index.d.ts +8 -0
- package/dist/tileset/index.d.ts.map +1 -0
- package/dist/tileset/index.js +7 -0
- package/dist/tileset/index.js.map +1 -0
- package/dist/tileset/tile-2d-header.d.ts +71 -0
- package/dist/tileset/tile-2d-header.d.ts.map +1 -0
- package/dist/tileset/tile-2d-header.js +168 -0
- package/dist/tileset/tile-2d-header.js.map +1 -0
- package/dist/tileset/tileset-2d.d.ts +210 -0
- package/dist/tileset/tileset-2d.d.ts.map +1 -0
- package/dist/tileset/tileset-2d.js +531 -0
- package/dist/tileset/tileset-2d.js.map +1 -0
- package/dist/tileset/types.d.ts +44 -0
- package/dist/tileset/types.d.ts.map +1 -0
- package/dist/tileset/types.js +5 -0
- package/dist/tileset/types.js.map +1 -0
- package/dist/utils/memoize.d.ts +2 -0
- package/dist/utils/memoize.d.ts.map +1 -0
- package/dist/utils/memoize.js +36 -0
- package/dist/utils/memoize.js.map +1 -0
- package/package.json +17 -11
- package/src/global-grid-layer/global-grid-cluster-layer.ts +1 -1
- package/src/index.ts +14 -0
- package/src/shared-tile-2d-layer/deck-tile-traversal.ts +247 -0
- package/src/shared-tile-2d-layer/deck-tileset-adapter.ts +262 -0
- package/src/shared-tile-2d-layer/index.ts +7 -0
- package/src/shared-tile-2d-layer/shared-tile-2d-layer.ts +681 -0
- package/src/shared-tile-2d-layer/shared-tile-2d-view.ts +339 -0
- package/src/shared-tile-2d-layer/url-template.ts +40 -0
- package/src/tile-grid-layer/tile-grid-layer.ts +158 -0
- package/src/tile-source-layer/tile-source-layer.ts +2 -2
- package/src/tileset/adapter.ts +47 -0
- package/src/tileset/index.ts +22 -0
- package/src/tileset/tile-2d-header.ts +210 -0
- package/src/tileset/tileset-2d.ts +705 -0
- package/src/tileset/types.ts +38 -0
- package/src/utils/memoize.ts +38 -0
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,12 @@ __export(dist_exports, {
|
|
|
30
30
|
H3Grid: () => H3Grid,
|
|
31
31
|
QuadkeyGrid: () => QuadkeyGrid,
|
|
32
32
|
S2Grid: () => S2Grid,
|
|
33
|
-
|
|
33
|
+
SharedTile2DHeader: () => SharedTile2DHeader,
|
|
34
|
+
SharedTile2DLayer: () => SharedTile2DLayer,
|
|
35
|
+
SharedTileset2D: () => SharedTileset2D,
|
|
36
|
+
TileGridLayer: () => TileGridLayer,
|
|
37
|
+
TileSourceLayer: () => TileSourceLayer,
|
|
38
|
+
sharedTile2DDeckAdapter: () => sharedTile2DDeckAdapter
|
|
34
39
|
});
|
|
35
40
|
module.exports = __toCommonJS(dist_exports);
|
|
36
41
|
|
|
@@ -133,6 +138,1793 @@ function renderSubLayers(props) {
|
|
|
133
138
|
return layers;
|
|
134
139
|
}
|
|
135
140
|
|
|
141
|
+
// dist/shared-tile-2d-layer/shared-tile-2d-layer.js
|
|
142
|
+
var import_core4 = require("@deck.gl/core");
|
|
143
|
+
var import_layers2 = require("@deck.gl/layers");
|
|
144
|
+
var import_core5 = require("@math.gl/core");
|
|
145
|
+
|
|
146
|
+
// dist/tileset/tileset-2d.js
|
|
147
|
+
var import_loader_utils = require("@loaders.gl/loader-utils");
|
|
148
|
+
var import_stats = require("@probe.gl/stats");
|
|
149
|
+
|
|
150
|
+
// dist/tileset/tile-2d-header.js
|
|
151
|
+
var SharedTile2DHeader = class {
|
|
152
|
+
/** x/y/z tile coordinate. */
|
|
153
|
+
index;
|
|
154
|
+
/** Closest cached ancestor tile in the current tree. */
|
|
155
|
+
parent;
|
|
156
|
+
/** Cached child tiles beneath this tile. */
|
|
157
|
+
children;
|
|
158
|
+
/** Loaded tile payload. */
|
|
159
|
+
content;
|
|
160
|
+
/** Stable tile cache id. */
|
|
161
|
+
id;
|
|
162
|
+
/** Resolved zoom level for the tile. */
|
|
163
|
+
zoom;
|
|
164
|
+
/** Optional application data associated with the tile. */
|
|
165
|
+
userData;
|
|
166
|
+
/** Bounds represented as `[[minX, minY], [maxX, maxY]]` for loaders.gl compatibility. */
|
|
167
|
+
boundingBox;
|
|
168
|
+
/** Abort controller for the current request, if one exists. */
|
|
169
|
+
_abortController;
|
|
170
|
+
/** Promise tracking the in-flight tile load, if any. */
|
|
171
|
+
_loader;
|
|
172
|
+
/** Monotonic request id used to ignore stale responses. */
|
|
173
|
+
_loaderId;
|
|
174
|
+
/** Indicates whether the last request completed successfully. */
|
|
175
|
+
_isLoaded;
|
|
176
|
+
/** Indicates whether the current request was cancelled. */
|
|
177
|
+
_isCancelled;
|
|
178
|
+
/** Indicates whether the tile should be refreshed. */
|
|
179
|
+
_needsReload;
|
|
180
|
+
/** Structured bounds assigned when the tile is created. */
|
|
181
|
+
_bbox;
|
|
182
|
+
/** Creates a tile header for a specific tile index. */
|
|
183
|
+
constructor(index) {
|
|
184
|
+
this.index = index;
|
|
185
|
+
this.parent = null;
|
|
186
|
+
this.children = [];
|
|
187
|
+
this.content = null;
|
|
188
|
+
this._loader = void 0;
|
|
189
|
+
this._abortController = null;
|
|
190
|
+
this._loaderId = 0;
|
|
191
|
+
this._isLoaded = false;
|
|
192
|
+
this._isCancelled = false;
|
|
193
|
+
this._needsReload = false;
|
|
194
|
+
}
|
|
195
|
+
/** Structured bounds for the tile in the active coordinate system. */
|
|
196
|
+
get bbox() {
|
|
197
|
+
return this._bbox;
|
|
198
|
+
}
|
|
199
|
+
/** Initializes the tile bounds once during tile creation. */
|
|
200
|
+
set bbox(value) {
|
|
201
|
+
if (this._bbox)
|
|
202
|
+
return;
|
|
203
|
+
this._bbox = value;
|
|
204
|
+
if ("west" in value) {
|
|
205
|
+
this.boundingBox = [
|
|
206
|
+
[value.west, value.south],
|
|
207
|
+
[value.east, value.north]
|
|
208
|
+
];
|
|
209
|
+
} else {
|
|
210
|
+
this.boundingBox = [
|
|
211
|
+
[value.left, value.top],
|
|
212
|
+
[value.right, value.bottom]
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/** Resolves to loaded content while a request is in flight, otherwise returns the cached content. */
|
|
217
|
+
get data() {
|
|
218
|
+
const loader = this._loader;
|
|
219
|
+
if (!this._isCancelled && loader !== void 0) {
|
|
220
|
+
return loader.then(() => this.data);
|
|
221
|
+
}
|
|
222
|
+
return this.content;
|
|
223
|
+
}
|
|
224
|
+
/** Indicates whether tile content is available and up to date. */
|
|
225
|
+
get isLoaded() {
|
|
226
|
+
return this._isLoaded && !this._needsReload;
|
|
227
|
+
}
|
|
228
|
+
/** Indicates whether a tile request is currently in flight. */
|
|
229
|
+
get isLoading() {
|
|
230
|
+
return Boolean(this._loader) && !this._isCancelled;
|
|
231
|
+
}
|
|
232
|
+
/** Indicates whether the tile should be requested again. */
|
|
233
|
+
get needsReload() {
|
|
234
|
+
return this._needsReload || this._isCancelled;
|
|
235
|
+
}
|
|
236
|
+
/** Estimated byte size of the cached payload. */
|
|
237
|
+
get byteLength() {
|
|
238
|
+
const result = this.content ? this.content.byteLength : 0;
|
|
239
|
+
return Number.isFinite(result) ? result : 0;
|
|
240
|
+
}
|
|
241
|
+
/** Internal request pipeline used by {@link loadData}. */
|
|
242
|
+
async _loadData({ getData, requestScheduler, onLoad, onError }) {
|
|
243
|
+
const completeLoad = (tileData2, error2, loaderId2) => {
|
|
244
|
+
if (loaderId2 !== this._loaderId) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
this._loader = void 0;
|
|
248
|
+
this.content = tileData2;
|
|
249
|
+
if (this._isCancelled && !tileData2) {
|
|
250
|
+
this._isLoaded = false;
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
this._isLoaded = true;
|
|
254
|
+
this._isCancelled = false;
|
|
255
|
+
if (error2) {
|
|
256
|
+
onError(error2, this);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
onLoad(this);
|
|
260
|
+
};
|
|
261
|
+
const { index, id, bbox, userData, zoom } = this;
|
|
262
|
+
const loaderId = this._loaderId;
|
|
263
|
+
this._abortController = new AbortController();
|
|
264
|
+
const { signal } = this._abortController;
|
|
265
|
+
const requestToken = await requestScheduler.scheduleRequest(this, () => 1);
|
|
266
|
+
if (!requestToken) {
|
|
267
|
+
this._isCancelled = true;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (this._isCancelled) {
|
|
271
|
+
requestToken.done();
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
let tileData = null;
|
|
275
|
+
let error;
|
|
276
|
+
try {
|
|
277
|
+
tileData = await getData({ index, id, bbox, userData, zoom, signal });
|
|
278
|
+
} catch (err) {
|
|
279
|
+
error = err || true;
|
|
280
|
+
} finally {
|
|
281
|
+
requestToken.done();
|
|
282
|
+
}
|
|
283
|
+
completeLoad(tileData, error, loaderId);
|
|
284
|
+
}
|
|
285
|
+
/** Loads tile data through the shared scheduler. */
|
|
286
|
+
loadData(opts) {
|
|
287
|
+
this._isLoaded = false;
|
|
288
|
+
this._isCancelled = false;
|
|
289
|
+
this._needsReload = false;
|
|
290
|
+
this._loaderId++;
|
|
291
|
+
this._loader = this._loadData(opts);
|
|
292
|
+
return this._loader;
|
|
293
|
+
}
|
|
294
|
+
/** Marks the tile stale so it is refreshed on the next traversal. */
|
|
295
|
+
setNeedsReload() {
|
|
296
|
+
if (this.isLoading) {
|
|
297
|
+
this.abort();
|
|
298
|
+
this._loader = void 0;
|
|
299
|
+
}
|
|
300
|
+
this._needsReload = true;
|
|
301
|
+
}
|
|
302
|
+
/** Cancels an in-flight tile request. */
|
|
303
|
+
abort() {
|
|
304
|
+
var _a;
|
|
305
|
+
if (this.isLoaded) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
this._isCancelled = true;
|
|
309
|
+
(_a = this._abortController) == null ? void 0 : _a.abort();
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
// dist/tileset/tileset-2d.js
|
|
314
|
+
var STRATEGY_NEVER = "never";
|
|
315
|
+
var STRATEGY_REPLACE = "no-overlap";
|
|
316
|
+
var STRATEGY_DEFAULT = "best-available";
|
|
317
|
+
var DEFAULT_TILESET2D_PROPS = {
|
|
318
|
+
adapter: null,
|
|
319
|
+
extent: null,
|
|
320
|
+
tileSize: 512,
|
|
321
|
+
maxZoom: null,
|
|
322
|
+
minZoom: null,
|
|
323
|
+
maxCacheSize: 100,
|
|
324
|
+
maxCacheByteSize: null,
|
|
325
|
+
refinementStrategy: "best-available",
|
|
326
|
+
zRange: null,
|
|
327
|
+
maxRequests: 6,
|
|
328
|
+
debounceTime: 0,
|
|
329
|
+
zoomOffset: 0,
|
|
330
|
+
onTileLoad: () => {
|
|
331
|
+
},
|
|
332
|
+
onTileUnload: () => {
|
|
333
|
+
},
|
|
334
|
+
onTileError: () => {
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
var SharedTileset2D = class {
|
|
338
|
+
/** Live counters describing shared tileset state. */
|
|
339
|
+
stats;
|
|
340
|
+
/** Effective runtime options after defaults and metadata overrides have been applied. */
|
|
341
|
+
opts;
|
|
342
|
+
/** Cached metadata returned by the backing TileSource, if any. */
|
|
343
|
+
sourceMetadata = null;
|
|
344
|
+
/** Scheduler shared across all tile requests for this tileset. */
|
|
345
|
+
_requestScheduler;
|
|
346
|
+
/** Shared tile cache keyed by tile id. */
|
|
347
|
+
_cache;
|
|
348
|
+
/** Tracks whether parent/child links need rebuilding. */
|
|
349
|
+
_dirty;
|
|
350
|
+
/** Cached tiles sorted by zoom for traversal and rendering. */
|
|
351
|
+
_tiles;
|
|
352
|
+
/** Running total of cached payload byte size. */
|
|
353
|
+
_cacheByteSize;
|
|
354
|
+
/** Cumulative number of tiles evicted from the shared cache. */
|
|
355
|
+
_unloadedTileCount;
|
|
356
|
+
/** Subscribers watching tileset lifecycle events. */
|
|
357
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
358
|
+
/** Selected and visible tiles tracked per consumer. */
|
|
359
|
+
_consumers = /* @__PURE__ */ new Map();
|
|
360
|
+
/** Option names explicitly set by the caller. */
|
|
361
|
+
_explicitOptionKeys = /* @__PURE__ */ new Set();
|
|
362
|
+
/** Caller-provided options before metadata-derived overrides are applied. */
|
|
363
|
+
_baseOpts = {};
|
|
364
|
+
/** Derived overrides sourced from TileSource metadata. */
|
|
365
|
+
_sourceMetadataOverrides = {};
|
|
366
|
+
/** Resolved maximum zoom level used by traversal. */
|
|
367
|
+
_maxZoom;
|
|
368
|
+
/** Resolved minimum zoom level used by traversal. */
|
|
369
|
+
_minZoom;
|
|
370
|
+
/** Most recent traversal context used to derive tile metadata. */
|
|
371
|
+
_lastTileContext = null;
|
|
372
|
+
/** Creates a tileset from either `getTileData` or a loaders.gl `TileSource`. */
|
|
373
|
+
constructor(opts) {
|
|
374
|
+
this.stats = new import_stats.Stats({
|
|
375
|
+
id: "SharedTileset2D",
|
|
376
|
+
stats: [
|
|
377
|
+
{ name: "Tiles In Cache" },
|
|
378
|
+
{ name: "Cache Size" },
|
|
379
|
+
{ name: "Visible Tiles" },
|
|
380
|
+
{ name: "Selected Tiles" },
|
|
381
|
+
{ name: "Loading Tiles" },
|
|
382
|
+
{ name: "Unloaded Tiles" },
|
|
383
|
+
{ name: "Consumers" }
|
|
384
|
+
]
|
|
385
|
+
});
|
|
386
|
+
this.opts = {
|
|
387
|
+
...DEFAULT_TILESET2D_PROPS,
|
|
388
|
+
...opts,
|
|
389
|
+
getTileData: opts.getTileData || (() => null),
|
|
390
|
+
tileSource: opts.tileSource
|
|
391
|
+
};
|
|
392
|
+
this._requestScheduler = new import_loader_utils.RequestScheduler({
|
|
393
|
+
throttleRequests: this.opts.maxRequests > 0 || this.opts.debounceTime > 0,
|
|
394
|
+
maxRequests: this.opts.maxRequests,
|
|
395
|
+
debounceTime: this.opts.debounceTime
|
|
396
|
+
});
|
|
397
|
+
this._cache = /* @__PURE__ */ new Map();
|
|
398
|
+
this._tiles = [];
|
|
399
|
+
this._dirty = false;
|
|
400
|
+
this._cacheByteSize = 0;
|
|
401
|
+
this._unloadedTileCount = 0;
|
|
402
|
+
if (!this.opts.tileSource && !opts.getTileData) {
|
|
403
|
+
throw new Error("SharedTileset2D requires either `getTileData` or `tileSource`.");
|
|
404
|
+
}
|
|
405
|
+
this.setOptions(opts);
|
|
406
|
+
this._updateStats();
|
|
407
|
+
if (this.opts.tileSource) {
|
|
408
|
+
this._initializeTileSource(this.opts.tileSource).catch(() => {
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/** Convenience factory for wrapping a loaders.gl `TileSource`. */
|
|
413
|
+
static fromTileSource(tileSource, opts = {}) {
|
|
414
|
+
return new SharedTileset2D({ ...opts, tileSource });
|
|
415
|
+
}
|
|
416
|
+
/** All tiles currently present in the shared cache. */
|
|
417
|
+
get tiles() {
|
|
418
|
+
return this._tiles;
|
|
419
|
+
}
|
|
420
|
+
/** Estimated byte size of all tile content currently retained in cache. */
|
|
421
|
+
get cacheByteSize() {
|
|
422
|
+
return this._cacheByteSize;
|
|
423
|
+
}
|
|
424
|
+
/** Union of tiles selected by all attached consumers. */
|
|
425
|
+
get selectedTiles() {
|
|
426
|
+
return Array.from(this._getSelectedTilesUnion());
|
|
427
|
+
}
|
|
428
|
+
/** Union of tiles contributing to the visible result across all consumers and views, including unloaded selected tiles. */
|
|
429
|
+
get visibleTiles() {
|
|
430
|
+
const union = this._getVisibleTilesUnion();
|
|
431
|
+
for (const tile of this._getSelectedTilesUnion()) {
|
|
432
|
+
union.add(tile);
|
|
433
|
+
}
|
|
434
|
+
return Array.from(union);
|
|
435
|
+
}
|
|
436
|
+
/** Tiles currently loading anywhere in the shared cache. */
|
|
437
|
+
get loadingTiles() {
|
|
438
|
+
return Array.from(this._cache.values()).filter((tile) => tile.isLoading);
|
|
439
|
+
}
|
|
440
|
+
/** Tiles retained in cache that do not currently have loaded content. */
|
|
441
|
+
get unloadedTiles() {
|
|
442
|
+
return Array.from(this._cache.values()).filter((tile) => !tile.isLoaded);
|
|
443
|
+
}
|
|
444
|
+
/** Maximum resolved zoom level after applying metadata and explicit options. */
|
|
445
|
+
get maxZoom() {
|
|
446
|
+
return this._maxZoom;
|
|
447
|
+
}
|
|
448
|
+
/** Minimum resolved zoom level after applying metadata and explicit options. */
|
|
449
|
+
get minZoom() {
|
|
450
|
+
return this._minZoom;
|
|
451
|
+
}
|
|
452
|
+
/** Active refinement strategy for placeholder handling. */
|
|
453
|
+
get refinementStrategy() {
|
|
454
|
+
return this.opts.refinementStrategy || STRATEGY_DEFAULT;
|
|
455
|
+
}
|
|
456
|
+
/** Adapter currently used for traversal and tile metadata. */
|
|
457
|
+
get adapter() {
|
|
458
|
+
return this.opts.adapter;
|
|
459
|
+
}
|
|
460
|
+
/** Subscribes to tileset lifecycle events. */
|
|
461
|
+
subscribe(listener) {
|
|
462
|
+
this._listeners.add(listener);
|
|
463
|
+
return () => this._listeners.delete(listener);
|
|
464
|
+
}
|
|
465
|
+
/** Registers a consumer so cache pruning can account for its selected tiles. */
|
|
466
|
+
attachConsumer(id) {
|
|
467
|
+
this._consumers.set(id, { selectedTiles: /* @__PURE__ */ new Set(), visibleTiles: /* @__PURE__ */ new Set() });
|
|
468
|
+
this._updateStats();
|
|
469
|
+
}
|
|
470
|
+
/** Unregisters a consumer and prunes unused requests and tiles. */
|
|
471
|
+
detachConsumer(id) {
|
|
472
|
+
this._consumers.delete(id);
|
|
473
|
+
this._pruneRequests();
|
|
474
|
+
this._resizeCache();
|
|
475
|
+
this._updateStats();
|
|
476
|
+
}
|
|
477
|
+
/** Updates tileset options and reapplies TileSource metadata overrides. */
|
|
478
|
+
setOptions(opts) {
|
|
479
|
+
this._rememberExplicitOptions(opts);
|
|
480
|
+
this._baseOpts = { ...this._baseOpts, ...opts };
|
|
481
|
+
this._applyResolvedOptions();
|
|
482
|
+
}
|
|
483
|
+
/** Aborts in-flight requests and clears the shared cache. */
|
|
484
|
+
finalize() {
|
|
485
|
+
for (const tile of this._cache.values()) {
|
|
486
|
+
if (tile.isLoading) {
|
|
487
|
+
tile.abort();
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
this._cache.clear();
|
|
491
|
+
this._tiles = [];
|
|
492
|
+
this._consumers.clear();
|
|
493
|
+
this._cacheByteSize = 0;
|
|
494
|
+
this._unloadedTileCount = 0;
|
|
495
|
+
this._updateStats();
|
|
496
|
+
}
|
|
497
|
+
/** Marks all retained tiles stale and drops unused cached tiles. */
|
|
498
|
+
reloadAll() {
|
|
499
|
+
const selectedTiles = this._getSelectedTilesUnion();
|
|
500
|
+
for (const id of this._cache.keys()) {
|
|
501
|
+
const tile = this._cache.get(id);
|
|
502
|
+
if (tile && !selectedTiles.has(tile)) {
|
|
503
|
+
this._cache.delete(id);
|
|
504
|
+
} else if (tile) {
|
|
505
|
+
tile.setNeedsReload();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
this._cacheByteSize = this._getCacheByteSize();
|
|
509
|
+
this.prepareTiles();
|
|
510
|
+
this._updateStats();
|
|
511
|
+
}
|
|
512
|
+
/** Updates the selected and visible tile sets for one consumer. */
|
|
513
|
+
updateConsumer(id, selectedTiles, visibleTiles) {
|
|
514
|
+
this._consumers.set(id, {
|
|
515
|
+
selectedTiles: new Set(selectedTiles),
|
|
516
|
+
visibleTiles: new Set(visibleTiles)
|
|
517
|
+
});
|
|
518
|
+
this._pruneRequests();
|
|
519
|
+
this._resizeCache();
|
|
520
|
+
this._updateStats();
|
|
521
|
+
}
|
|
522
|
+
/** Rebuilds parent/child links if the cache changed since the last traversal. */
|
|
523
|
+
prepareTiles() {
|
|
524
|
+
if (this._dirty) {
|
|
525
|
+
this._rebuildTree();
|
|
526
|
+
this._syncTiles();
|
|
527
|
+
this._dirty = false;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/** Returns tile indices needed to cover a viewport. */
|
|
531
|
+
getTileIndices({ viewState, maxZoom, minZoom, zRange, modelMatrix, modelMatrixInverse }) {
|
|
532
|
+
const { adapter, tileSize, extent, zoomOffset } = this.opts;
|
|
533
|
+
if (!adapter) {
|
|
534
|
+
throw new Error("SharedTileset2D requires an adapter before tile traversal can be used.");
|
|
535
|
+
}
|
|
536
|
+
this._lastTileContext = { viewState, tileSize };
|
|
537
|
+
return adapter.getTileIndices({
|
|
538
|
+
viewState,
|
|
539
|
+
maxZoom,
|
|
540
|
+
minZoom,
|
|
541
|
+
zRange,
|
|
542
|
+
tileSize,
|
|
543
|
+
extent: normalizeBounds(extent),
|
|
544
|
+
modelMatrix,
|
|
545
|
+
modelMatrixInverse,
|
|
546
|
+
zoomOffset
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
/** Returns the stable cache id for a tile index. */
|
|
550
|
+
getTileId(index) {
|
|
551
|
+
return `${index.x}-${index.y}-${index.z}`;
|
|
552
|
+
}
|
|
553
|
+
/** Returns the zoom level represented by a tile index. */
|
|
554
|
+
getTileZoom(index) {
|
|
555
|
+
return index.z;
|
|
556
|
+
}
|
|
557
|
+
/** Returns derived metadata used to initialize a tile header. */
|
|
558
|
+
getTileMetadata(index) {
|
|
559
|
+
if (!this._lastTileContext) {
|
|
560
|
+
throw new Error("SharedTileset2D metadata requested before traversal context was set.");
|
|
561
|
+
}
|
|
562
|
+
if (!this.opts.adapter) {
|
|
563
|
+
throw new Error("SharedTileset2D requires an adapter before tile metadata can be derived.");
|
|
564
|
+
}
|
|
565
|
+
return { bbox: this.opts.adapter.getTileBoundingBox(this._lastTileContext, index) };
|
|
566
|
+
}
|
|
567
|
+
/** Returns the parent tile index in the quadtree. */
|
|
568
|
+
getParentIndex(index) {
|
|
569
|
+
return { x: Math.floor(index.x / 2), y: Math.floor(index.y / 2), z: index.z - 1 };
|
|
570
|
+
}
|
|
571
|
+
getTile(index, create) {
|
|
572
|
+
const id = this.getTileId(index);
|
|
573
|
+
let tile = this._cache.get(id);
|
|
574
|
+
let needsReload = false;
|
|
575
|
+
if (!tile && create) {
|
|
576
|
+
tile = new SharedTile2DHeader(index);
|
|
577
|
+
Object.assign(tile, this.getTileMetadata(tile.index));
|
|
578
|
+
Object.assign(tile, { id, zoom: this.getTileZoom(tile.index) });
|
|
579
|
+
needsReload = true;
|
|
580
|
+
this._cache.set(id, tile);
|
|
581
|
+
this._dirty = true;
|
|
582
|
+
this._updateStats();
|
|
583
|
+
} else if (tile && tile.needsReload) {
|
|
584
|
+
needsReload = true;
|
|
585
|
+
}
|
|
586
|
+
if (tile) {
|
|
587
|
+
this._touchTile(id, tile);
|
|
588
|
+
}
|
|
589
|
+
if (tile && needsReload) {
|
|
590
|
+
tile.loadData({
|
|
591
|
+
getData: this.opts.getTileData,
|
|
592
|
+
requestScheduler: this._requestScheduler,
|
|
593
|
+
onLoad: this._handleTileLoad.bind(this),
|
|
594
|
+
onError: this._handleTileError.bind(this)
|
|
595
|
+
}).catch(() => {
|
|
596
|
+
});
|
|
597
|
+
this._updateStats();
|
|
598
|
+
}
|
|
599
|
+
return tile;
|
|
600
|
+
}
|
|
601
|
+
/** Loads metadata from a TileSource and reapplies derived option overrides. */
|
|
602
|
+
async _initializeTileSource(tileSource) {
|
|
603
|
+
try {
|
|
604
|
+
this.sourceMetadata = await tileSource.getMetadata();
|
|
605
|
+
this._sourceMetadataOverrides = this._getMetadataOverrides(this.sourceMetadata);
|
|
606
|
+
this._applyResolvedOptions();
|
|
607
|
+
this._notifyUpdate();
|
|
608
|
+
} catch (error) {
|
|
609
|
+
const normalizedError = error instanceof Error ? error : new Error(`TileSource metadata error: ${String(error)}`);
|
|
610
|
+
this._notifyError(normalizedError);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
/** Tracks which options were explicitly set by the caller. */
|
|
614
|
+
_rememberExplicitOptions(opts) {
|
|
615
|
+
for (const key of Object.keys(opts)) {
|
|
616
|
+
this._explicitOptionKeys.add(key);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
/** Resolves defaults, metadata overrides, and caller options into runtime settings. */
|
|
620
|
+
_applyResolvedOptions() {
|
|
621
|
+
const resolvedOpts = {
|
|
622
|
+
...DEFAULT_TILESET2D_PROPS,
|
|
623
|
+
...this._sourceMetadataOverrides,
|
|
624
|
+
...this._baseOpts
|
|
625
|
+
};
|
|
626
|
+
if (resolvedOpts.tileSource) {
|
|
627
|
+
const tileSource = resolvedOpts.tileSource;
|
|
628
|
+
resolvedOpts.getTileData = (loadProps) => tileSource.getTileData(loadProps);
|
|
629
|
+
}
|
|
630
|
+
this.opts = resolvedOpts;
|
|
631
|
+
this._maxZoom = typeof this.opts.maxZoom === "number" && Number.isFinite(this.opts.maxZoom) ? Math.floor(this.opts.maxZoom) : void 0;
|
|
632
|
+
this._minZoom = typeof this.opts.minZoom === "number" && Number.isFinite(this.opts.minZoom) ? Math.ceil(this.opts.minZoom) : void 0;
|
|
633
|
+
}
|
|
634
|
+
/** Maps TileSource metadata into supported tileset options. */
|
|
635
|
+
_getMetadataOverrides(metadata) {
|
|
636
|
+
if (!metadata) {
|
|
637
|
+
return {};
|
|
638
|
+
}
|
|
639
|
+
const overrides = {};
|
|
640
|
+
if (!this._explicitOptionKeys.has("minZoom") && Number.isFinite(metadata.minZoom)) {
|
|
641
|
+
overrides.minZoom = metadata.minZoom;
|
|
642
|
+
}
|
|
643
|
+
if (!this._explicitOptionKeys.has("maxZoom") && Number.isFinite(metadata.maxZoom)) {
|
|
644
|
+
overrides.maxZoom = metadata.maxZoom;
|
|
645
|
+
}
|
|
646
|
+
if (!this._explicitOptionKeys.has("extent") && metadata.boundingBox) {
|
|
647
|
+
overrides.extent = [
|
|
648
|
+
metadata.boundingBox[0][0],
|
|
649
|
+
metadata.boundingBox[0][1],
|
|
650
|
+
metadata.boundingBox[1][0],
|
|
651
|
+
metadata.boundingBox[1][1]
|
|
652
|
+
];
|
|
653
|
+
}
|
|
654
|
+
return overrides;
|
|
655
|
+
}
|
|
656
|
+
/** Handles successful tile loads. */
|
|
657
|
+
_handleTileLoad(tile) {
|
|
658
|
+
var _a, _b, _c;
|
|
659
|
+
(_b = (_a = this.opts).onTileLoad) == null ? void 0 : _b.call(_a, tile);
|
|
660
|
+
this._cacheByteSize = this._getCacheByteSize();
|
|
661
|
+
this._resizeCache();
|
|
662
|
+
for (const listener of this._listeners) {
|
|
663
|
+
(_c = listener.onTileLoad) == null ? void 0 : _c.call(listener, tile);
|
|
664
|
+
}
|
|
665
|
+
this._updateStats();
|
|
666
|
+
}
|
|
667
|
+
/** Handles tile load failures. */
|
|
668
|
+
_handleTileError(error, tile) {
|
|
669
|
+
var _a, _b, _c;
|
|
670
|
+
(_b = (_a = this.opts).onTileError) == null ? void 0 : _b.call(_a, error, tile);
|
|
671
|
+
for (const listener of this._listeners) {
|
|
672
|
+
(_c = listener.onTileError) == null ? void 0 : _c.call(listener, error, tile);
|
|
673
|
+
}
|
|
674
|
+
this._updateStats();
|
|
675
|
+
}
|
|
676
|
+
/** Handles tile eviction from cache. */
|
|
677
|
+
_handleTileUnload(tile) {
|
|
678
|
+
var _a, _b, _c;
|
|
679
|
+
this._unloadedTileCount++;
|
|
680
|
+
(_b = (_a = this.opts).onTileUnload) == null ? void 0 : _b.call(_a, tile);
|
|
681
|
+
for (const listener of this._listeners) {
|
|
682
|
+
(_c = listener.onTileUnload) == null ? void 0 : _c.call(listener, tile);
|
|
683
|
+
}
|
|
684
|
+
this._updateStats();
|
|
685
|
+
}
|
|
686
|
+
/** Notifies listeners that metadata or effective options changed. */
|
|
687
|
+
_notifyUpdate() {
|
|
688
|
+
var _a;
|
|
689
|
+
for (const listener of this._listeners) {
|
|
690
|
+
(_a = listener.onUpdate) == null ? void 0 : _a.call(listener);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/** Notifies listeners about asynchronous metadata errors. */
|
|
694
|
+
_notifyError(error) {
|
|
695
|
+
var _a;
|
|
696
|
+
for (const listener of this._listeners) {
|
|
697
|
+
(_a = listener.onError) == null ? void 0 : _a.call(listener, error);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
/** Recomputes absolute counter stats and notifies listeners. */
|
|
701
|
+
_updateStats() {
|
|
702
|
+
var _a;
|
|
703
|
+
this._setStatCount("Tiles In Cache", this._cache.size);
|
|
704
|
+
this._setStatCount("Cache Size", this.cacheByteSize);
|
|
705
|
+
this._setStatCount("Visible Tiles", this.visibleTiles.length);
|
|
706
|
+
this._setStatCount("Selected Tiles", this.selectedTiles.length);
|
|
707
|
+
this._setStatCount("Loading Tiles", this.loadingTiles.length);
|
|
708
|
+
this._setStatCount("Unloaded Tiles", this._unloadedTileCount);
|
|
709
|
+
this._setStatCount("Consumers", this._consumers.size);
|
|
710
|
+
for (const listener of this._listeners) {
|
|
711
|
+
(_a = listener.onStatsChange) == null ? void 0 : _a.call(listener, this.stats);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
/** Writes an absolute count into a probe.gl stat. */
|
|
715
|
+
_setStatCount(name, value) {
|
|
716
|
+
this.stats.get(name).reset().addCount(value);
|
|
717
|
+
}
|
|
718
|
+
/** Returns the union of selected tiles across all consumers. */
|
|
719
|
+
_getSelectedTilesUnion() {
|
|
720
|
+
const union = /* @__PURE__ */ new Set();
|
|
721
|
+
for (const consumer of this._consumers.values()) {
|
|
722
|
+
for (const tile of consumer.selectedTiles) {
|
|
723
|
+
union.add(tile);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
return union;
|
|
727
|
+
}
|
|
728
|
+
/** Returns the union of visible tiles across all consumers. */
|
|
729
|
+
_getVisibleTilesUnion() {
|
|
730
|
+
const union = /* @__PURE__ */ new Set();
|
|
731
|
+
for (const consumer of this._consumers.values()) {
|
|
732
|
+
for (const tile of consumer.visibleTiles) {
|
|
733
|
+
union.add(tile);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return union;
|
|
737
|
+
}
|
|
738
|
+
/** Moves a touched tile to the back of the cache map for LRU eviction ordering. */
|
|
739
|
+
_touchTile(id, tile) {
|
|
740
|
+
this._cache.delete(id);
|
|
741
|
+
this._cache.set(id, tile);
|
|
742
|
+
}
|
|
743
|
+
/** Computes the total byte size of all cached tile content. */
|
|
744
|
+
_getCacheByteSize() {
|
|
745
|
+
let byteLength = 0;
|
|
746
|
+
for (const tile of this._cache.values()) {
|
|
747
|
+
byteLength += tile.byteLength;
|
|
748
|
+
}
|
|
749
|
+
return byteLength;
|
|
750
|
+
}
|
|
751
|
+
/** Cancels low-priority requests when consumers no longer need them. */
|
|
752
|
+
_pruneRequests() {
|
|
753
|
+
const { maxRequests = 0 } = this.opts;
|
|
754
|
+
const selectedTiles = this._getSelectedTilesUnion();
|
|
755
|
+
const visibleTiles = this._getVisibleTilesUnion();
|
|
756
|
+
const abortCandidates = [];
|
|
757
|
+
let ongoingRequestCount = 0;
|
|
758
|
+
for (const tile of this._cache.values()) {
|
|
759
|
+
if (tile.isLoading) {
|
|
760
|
+
ongoingRequestCount++;
|
|
761
|
+
if (!selectedTiles.has(tile) && !visibleTiles.has(tile)) {
|
|
762
|
+
abortCandidates.push(tile);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
while (maxRequests > 0 && ongoingRequestCount > maxRequests && abortCandidates.length > 0) {
|
|
767
|
+
const tile = abortCandidates.shift();
|
|
768
|
+
if (tile) {
|
|
769
|
+
tile.abort();
|
|
770
|
+
}
|
|
771
|
+
ongoingRequestCount--;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/** Rebuilds parent and child links for all cached tiles. */
|
|
775
|
+
_rebuildTree() {
|
|
776
|
+
for (const tile of this._cache.values()) {
|
|
777
|
+
tile.parent = null;
|
|
778
|
+
if (tile.children) {
|
|
779
|
+
tile.children.length = 0;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
for (const tile of this._cache.values()) {
|
|
783
|
+
const parent = this._getNearestAncestor(tile);
|
|
784
|
+
tile.parent = parent;
|
|
785
|
+
if (parent == null ? void 0 : parent.children) {
|
|
786
|
+
parent.children.push(tile);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
/** Updates the sorted tile list used by traversal and rendering. */
|
|
791
|
+
_syncTiles() {
|
|
792
|
+
this._tiles = Array.from(this._cache.values()).sort((t1, t2) => t1.zoom - t2.zoom);
|
|
793
|
+
}
|
|
794
|
+
/** Evicts unused cached tiles when configured cache limits are exceeded. */
|
|
795
|
+
_resizeCache() {
|
|
796
|
+
const maxCacheSize = this.opts.maxCacheSize ?? 100;
|
|
797
|
+
const maxCacheByteSize = this.opts.maxCacheByteSize ?? Infinity;
|
|
798
|
+
const visibleTiles = this._getVisibleTilesUnion();
|
|
799
|
+
const selectedTiles = this._getSelectedTilesUnion();
|
|
800
|
+
const overflown = this._cache.size > maxCacheSize || this._cacheByteSize > maxCacheByteSize;
|
|
801
|
+
if (overflown) {
|
|
802
|
+
for (const [id, tile] of this._cache) {
|
|
803
|
+
if (!visibleTiles.has(tile) && !selectedTiles.has(tile)) {
|
|
804
|
+
this._cache.delete(id);
|
|
805
|
+
this._cacheByteSize = this._getCacheByteSize();
|
|
806
|
+
this._handleTileUnload(tile);
|
|
807
|
+
}
|
|
808
|
+
if (this._cache.size <= maxCacheSize && this._cacheByteSize <= maxCacheByteSize) {
|
|
809
|
+
break;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
this._dirty = true;
|
|
813
|
+
}
|
|
814
|
+
if (this._dirty) {
|
|
815
|
+
this._rebuildTree();
|
|
816
|
+
this._syncTiles();
|
|
817
|
+
this._dirty = false;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/** Finds the nearest cached ancestor tile for placeholder rendering. */
|
|
821
|
+
_getNearestAncestor(tile) {
|
|
822
|
+
const { _minZoom = 0 } = this;
|
|
823
|
+
let index = tile.index;
|
|
824
|
+
while (this.getTileZoom(index) > _minZoom) {
|
|
825
|
+
index = this.getParentIndex(index);
|
|
826
|
+
const parent = this.getTile(index);
|
|
827
|
+
if (parent) {
|
|
828
|
+
return parent;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return null;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
function normalizeBounds(extent) {
|
|
835
|
+
return extent && extent.length === 4 ? extent : void 0;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// dist/shared-tile-2d-layer/shared-tile-2d-view.js
|
|
839
|
+
var import_core3 = require("@math.gl/core");
|
|
840
|
+
|
|
841
|
+
// dist/utils/memoize.js
|
|
842
|
+
function memoize(compute) {
|
|
843
|
+
let cachedArgs = {};
|
|
844
|
+
let cachedResult;
|
|
845
|
+
return (args) => {
|
|
846
|
+
for (const key in args) {
|
|
847
|
+
if (!isEqual(args[key], cachedArgs[key])) {
|
|
848
|
+
cachedResult = compute(args);
|
|
849
|
+
cachedArgs = args;
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return cachedResult;
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
function isEqual(a, b) {
|
|
857
|
+
if (a === b) {
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
if (Array.isArray(a)) {
|
|
861
|
+
const len = a.length;
|
|
862
|
+
if (!b || b.length !== len) {
|
|
863
|
+
return false;
|
|
864
|
+
}
|
|
865
|
+
for (let i = 0; i < len; i++) {
|
|
866
|
+
if (a[i] !== b[i]) {
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return true;
|
|
871
|
+
}
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// dist/shared-tile-2d-layer/deck-tile-traversal.js
|
|
876
|
+
var import_core2 = require("@deck.gl/core");
|
|
877
|
+
var import_culling = require("@math.gl/culling");
|
|
878
|
+
var import_web_mercator = require("@math.gl/web-mercator");
|
|
879
|
+
var TILE_SIZE = 512;
|
|
880
|
+
var MAX_MAPS = 3;
|
|
881
|
+
var REF_POINTS_5 = [
|
|
882
|
+
[0.5, 0.5],
|
|
883
|
+
[0, 0],
|
|
884
|
+
[0, 1],
|
|
885
|
+
[1, 0],
|
|
886
|
+
[1, 1]
|
|
887
|
+
];
|
|
888
|
+
var REF_POINTS_9 = REF_POINTS_5.concat([
|
|
889
|
+
[0, 0.5],
|
|
890
|
+
[0.5, 0],
|
|
891
|
+
[1, 0.5],
|
|
892
|
+
[0.5, 1]
|
|
893
|
+
]);
|
|
894
|
+
var REF_POINTS_11 = REF_POINTS_9.concat([
|
|
895
|
+
[0.25, 0.5],
|
|
896
|
+
[0.75, 0.5]
|
|
897
|
+
]);
|
|
898
|
+
var OSMNode = class {
|
|
899
|
+
x;
|
|
900
|
+
y;
|
|
901
|
+
z;
|
|
902
|
+
childVisible;
|
|
903
|
+
selected;
|
|
904
|
+
_children;
|
|
905
|
+
constructor(x, y, z) {
|
|
906
|
+
this.x = x;
|
|
907
|
+
this.y = y;
|
|
908
|
+
this.z = z;
|
|
909
|
+
}
|
|
910
|
+
get children() {
|
|
911
|
+
if (!this._children) {
|
|
912
|
+
const x = this.x * 2;
|
|
913
|
+
const y = this.y * 2;
|
|
914
|
+
const z = this.z + 1;
|
|
915
|
+
this._children = [
|
|
916
|
+
new OSMNode(x, y, z),
|
|
917
|
+
new OSMNode(x, y + 1, z),
|
|
918
|
+
new OSMNode(x + 1, y, z),
|
|
919
|
+
new OSMNode(x + 1, y + 1, z)
|
|
920
|
+
];
|
|
921
|
+
}
|
|
922
|
+
return this._children;
|
|
923
|
+
}
|
|
924
|
+
update(params) {
|
|
925
|
+
const { viewport, cullingVolume, elevationBounds, minZ, maxZ, bounds, offset, project } = params;
|
|
926
|
+
const boundingVolume = this.getBoundingVolume(elevationBounds, offset, project);
|
|
927
|
+
if (bounds && !this.insideBounds(bounds)) {
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
const isInside = cullingVolume.computeVisibility(boundingVolume);
|
|
931
|
+
if (isInside < 0) {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
if (!this.childVisible) {
|
|
935
|
+
let { z } = this;
|
|
936
|
+
if (z < maxZ && z >= minZ) {
|
|
937
|
+
const distance = boundingVolume.distanceTo(viewport.cameraPosition) * viewport.scale / viewport.height;
|
|
938
|
+
z += Math.floor(Math.log2(distance));
|
|
939
|
+
}
|
|
940
|
+
if (z >= maxZ) {
|
|
941
|
+
this.selected = true;
|
|
942
|
+
return true;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
this.selected = false;
|
|
946
|
+
this.childVisible = true;
|
|
947
|
+
for (const child of this.children) {
|
|
948
|
+
child.update(params);
|
|
949
|
+
}
|
|
950
|
+
return true;
|
|
951
|
+
}
|
|
952
|
+
getSelected(result = []) {
|
|
953
|
+
if (this.selected) {
|
|
954
|
+
result.push(this);
|
|
955
|
+
}
|
|
956
|
+
if (this._children) {
|
|
957
|
+
for (const node of this._children) {
|
|
958
|
+
node.getSelected(result);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return result;
|
|
962
|
+
}
|
|
963
|
+
insideBounds([minX, minY, maxX, maxY]) {
|
|
964
|
+
const scale = Math.pow(2, this.z);
|
|
965
|
+
const extent = TILE_SIZE / scale;
|
|
966
|
+
return this.x * extent < maxX && this.y * extent < maxY && (this.x + 1) * extent > minX && (this.y + 1) * extent > minY;
|
|
967
|
+
}
|
|
968
|
+
getBoundingVolume(zRange, worldOffset, project) {
|
|
969
|
+
if (project) {
|
|
970
|
+
const refPoints = this.z < 1 ? REF_POINTS_11 : this.z < 2 ? REF_POINTS_9 : REF_POINTS_5;
|
|
971
|
+
const refPointPositions = [];
|
|
972
|
+
for (const p of refPoints) {
|
|
973
|
+
const lngLat = osmTile2lngLat(this.x + p[0], this.y + p[1], this.z);
|
|
974
|
+
lngLat[2] = zRange[0];
|
|
975
|
+
refPointPositions.push(project(lngLat));
|
|
976
|
+
if (zRange[0] !== zRange[1]) {
|
|
977
|
+
lngLat[2] = zRange[1];
|
|
978
|
+
refPointPositions.push(project(lngLat));
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return (0, import_culling.makeOrientedBoundingBoxFromPoints)(refPointPositions);
|
|
982
|
+
}
|
|
983
|
+
const scale = Math.pow(2, this.z);
|
|
984
|
+
const extent = TILE_SIZE / scale;
|
|
985
|
+
const originX = this.x * extent + worldOffset * TILE_SIZE;
|
|
986
|
+
const originY = TILE_SIZE - (this.y + 1) * extent;
|
|
987
|
+
return new import_culling.AxisAlignedBoundingBox([originX, originY, zRange[0]], [originX + extent, originY + extent, zRange[1]]);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
function getOSMTileIndices(viewport, maxZ, zRange, bounds) {
|
|
991
|
+
const project = viewport instanceof import_core2._GlobeViewport && viewport.resolution ? (xyz) => viewport.projectPosition(xyz) : null;
|
|
992
|
+
const planes = Object.values(viewport.getFrustumPlanes()).map(({ normal, distance }) => new import_culling.Plane(normal.clone().negate(), distance));
|
|
993
|
+
const cullingVolume = new import_culling.CullingVolume(planes);
|
|
994
|
+
const unitsPerMeter = viewport.distanceScales.unitsPerMeter[2];
|
|
995
|
+
const elevationMin = zRange && zRange[0] * unitsPerMeter || 0;
|
|
996
|
+
const elevationMax = zRange && zRange[1] * unitsPerMeter || 0;
|
|
997
|
+
const minZ = viewport instanceof import_core2.WebMercatorViewport && viewport.pitch <= 60 ? maxZ : 0;
|
|
998
|
+
if (bounds) {
|
|
999
|
+
const [minLng, minLat, maxLng, maxLat] = bounds;
|
|
1000
|
+
const topLeft = (0, import_web_mercator.lngLatToWorld)([minLng, maxLat]);
|
|
1001
|
+
const bottomRight = (0, import_web_mercator.lngLatToWorld)([maxLng, minLat]);
|
|
1002
|
+
bounds = [topLeft[0], TILE_SIZE - topLeft[1], bottomRight[0], TILE_SIZE - bottomRight[1]];
|
|
1003
|
+
}
|
|
1004
|
+
const root = new OSMNode(0, 0, 0);
|
|
1005
|
+
const traversalParams = {
|
|
1006
|
+
viewport,
|
|
1007
|
+
project,
|
|
1008
|
+
cullingVolume,
|
|
1009
|
+
elevationBounds: [elevationMin, elevationMax],
|
|
1010
|
+
minZ,
|
|
1011
|
+
maxZ,
|
|
1012
|
+
bounds,
|
|
1013
|
+
offset: 0
|
|
1014
|
+
};
|
|
1015
|
+
root.update(traversalParams);
|
|
1016
|
+
updateWrappedWorldCopies(root, traversalParams, viewport);
|
|
1017
|
+
return root.getSelected();
|
|
1018
|
+
}
|
|
1019
|
+
function updateWrappedWorldCopies(root, traversalParams, viewport) {
|
|
1020
|
+
if (!(viewport instanceof import_core2.WebMercatorViewport) || !viewport.subViewports || viewport.subViewports.length <= 1) {
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
sweepOffsets(root, traversalParams, -1, -MAX_MAPS);
|
|
1024
|
+
sweepOffsets(root, traversalParams, 1, MAX_MAPS);
|
|
1025
|
+
}
|
|
1026
|
+
function sweepOffsets(root, traversalParams, startOffset, limit) {
|
|
1027
|
+
traversalParams.offset = startOffset;
|
|
1028
|
+
while (root.update(traversalParams)) {
|
|
1029
|
+
traversalParams.offset += Math.sign(startOffset);
|
|
1030
|
+
if (startOffset < 0 && traversalParams.offset < limit || startOffset > 0 && traversalParams.offset > limit) {
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// dist/shared-tile-2d-layer/deck-tileset-adapter.js
|
|
1037
|
+
var TILE_SIZE2 = 512;
|
|
1038
|
+
var DEFAULT_EXTENT = [-Infinity, -Infinity, Infinity, Infinity];
|
|
1039
|
+
function transformBox(bbox, modelMatrix) {
|
|
1040
|
+
const transformedCoords = [
|
|
1041
|
+
modelMatrix.transformAsPoint([bbox[0], bbox[1]]),
|
|
1042
|
+
modelMatrix.transformAsPoint([bbox[2], bbox[1]]),
|
|
1043
|
+
modelMatrix.transformAsPoint([bbox[0], bbox[3]]),
|
|
1044
|
+
modelMatrix.transformAsPoint([bbox[2], bbox[3]])
|
|
1045
|
+
];
|
|
1046
|
+
return [
|
|
1047
|
+
Math.min(...transformedCoords.map((i) => i[0])),
|
|
1048
|
+
Math.min(...transformedCoords.map((i) => i[1])),
|
|
1049
|
+
Math.max(...transformedCoords.map((i) => i[0])),
|
|
1050
|
+
Math.max(...transformedCoords.map((i) => i[1]))
|
|
1051
|
+
];
|
|
1052
|
+
}
|
|
1053
|
+
function getBoundingBox(viewport, zRange, extent) {
|
|
1054
|
+
let bounds;
|
|
1055
|
+
if (zRange && zRange.length === 2) {
|
|
1056
|
+
const [minZ, maxZ] = zRange;
|
|
1057
|
+
const bounds0 = viewport.getBounds({ z: minZ });
|
|
1058
|
+
const bounds1 = viewport.getBounds({ z: maxZ });
|
|
1059
|
+
bounds = [
|
|
1060
|
+
Math.min(bounds0[0], bounds1[0]),
|
|
1061
|
+
Math.min(bounds0[1], bounds1[1]),
|
|
1062
|
+
Math.max(bounds0[2], bounds1[2]),
|
|
1063
|
+
Math.max(bounds0[3], bounds1[3])
|
|
1064
|
+
];
|
|
1065
|
+
} else {
|
|
1066
|
+
bounds = viewport.getBounds();
|
|
1067
|
+
}
|
|
1068
|
+
if (!viewport.isGeospatial) {
|
|
1069
|
+
return [
|
|
1070
|
+
Math.max(Math.min(bounds[0], extent[2]), extent[0]),
|
|
1071
|
+
Math.max(Math.min(bounds[1], extent[3]), extent[1]),
|
|
1072
|
+
Math.min(Math.max(bounds[2], extent[0]), extent[2]),
|
|
1073
|
+
Math.min(Math.max(bounds[3], extent[1]), extent[3])
|
|
1074
|
+
];
|
|
1075
|
+
}
|
|
1076
|
+
return [
|
|
1077
|
+
Math.max(bounds[0], extent[0]),
|
|
1078
|
+
Math.max(bounds[1], extent[1]),
|
|
1079
|
+
Math.min(bounds[2], extent[2]),
|
|
1080
|
+
Math.min(bounds[3], extent[3])
|
|
1081
|
+
];
|
|
1082
|
+
}
|
|
1083
|
+
function getCullBounds({ viewport, z, cullRect }) {
|
|
1084
|
+
const subViewports = viewport.subViewports || [viewport];
|
|
1085
|
+
return subViewports.map((v) => getCullBoundsInViewport(v, z || 0, cullRect));
|
|
1086
|
+
}
|
|
1087
|
+
function getCullBoundsInViewport(viewport, z, cullRect) {
|
|
1088
|
+
if (!Array.isArray(z)) {
|
|
1089
|
+
const x = cullRect.x - viewport.x;
|
|
1090
|
+
const y = cullRect.y - viewport.y;
|
|
1091
|
+
const { width, height } = cullRect;
|
|
1092
|
+
const unprojectOption = { targetZ: z };
|
|
1093
|
+
const topLeft = viewport.unproject([x, y], unprojectOption);
|
|
1094
|
+
const topRight = viewport.unproject([x + width, y], unprojectOption);
|
|
1095
|
+
const bottomLeft = viewport.unproject([x, y + height], unprojectOption);
|
|
1096
|
+
const bottomRight = viewport.unproject([x + width, y + height], unprojectOption);
|
|
1097
|
+
return [
|
|
1098
|
+
Math.min(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
|
|
1099
|
+
Math.min(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1]),
|
|
1100
|
+
Math.max(topLeft[0], topRight[0], bottomLeft[0], bottomRight[0]),
|
|
1101
|
+
Math.max(topLeft[1], topRight[1], bottomLeft[1], bottomRight[1])
|
|
1102
|
+
];
|
|
1103
|
+
}
|
|
1104
|
+
const bounds0 = getCullBoundsInViewport(viewport, z[0], cullRect);
|
|
1105
|
+
const bounds1 = getCullBoundsInViewport(viewport, z[1], cullRect);
|
|
1106
|
+
return [
|
|
1107
|
+
Math.min(bounds0[0], bounds1[0]),
|
|
1108
|
+
Math.min(bounds0[1], bounds1[1]),
|
|
1109
|
+
Math.max(bounds0[2], bounds1[2]),
|
|
1110
|
+
Math.max(bounds0[3], bounds1[3])
|
|
1111
|
+
];
|
|
1112
|
+
}
|
|
1113
|
+
function getIndexingCoords(bbox, scale, modelMatrixInverse) {
|
|
1114
|
+
if (modelMatrixInverse) {
|
|
1115
|
+
return transformBox(bbox, modelMatrixInverse).map((i) => i * scale / TILE_SIZE2);
|
|
1116
|
+
}
|
|
1117
|
+
return bbox.map((i) => i * scale / TILE_SIZE2);
|
|
1118
|
+
}
|
|
1119
|
+
function getScale(z, tileSize) {
|
|
1120
|
+
return Math.pow(2, z) * TILE_SIZE2 / tileSize;
|
|
1121
|
+
}
|
|
1122
|
+
function osmTile2lngLat(x, y, z) {
|
|
1123
|
+
const scale = getScale(z, TILE_SIZE2);
|
|
1124
|
+
const lng = x / scale * 360 - 180;
|
|
1125
|
+
const n = Math.PI - 2 * Math.PI * y / scale;
|
|
1126
|
+
const lat = 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
|
1127
|
+
return [lng, lat];
|
|
1128
|
+
}
|
|
1129
|
+
function tile2XY(x, y, z, tileSize) {
|
|
1130
|
+
const scale = getScale(z, tileSize);
|
|
1131
|
+
return [x / scale * TILE_SIZE2, y / scale * TILE_SIZE2];
|
|
1132
|
+
}
|
|
1133
|
+
function tileToBoundingBox(viewport, x, y, z, tileSize = TILE_SIZE2) {
|
|
1134
|
+
if (viewport.isGeospatial) {
|
|
1135
|
+
const [west, north] = osmTile2lngLat(x, y, z);
|
|
1136
|
+
const [east, south] = osmTile2lngLat(x + 1, y + 1, z);
|
|
1137
|
+
return { west, north, east, south };
|
|
1138
|
+
}
|
|
1139
|
+
const [left, top] = tile2XY(x, y, z, tileSize);
|
|
1140
|
+
const [right, bottom] = tile2XY(x + 1, y + 1, z, tileSize);
|
|
1141
|
+
return { left, top, right, bottom };
|
|
1142
|
+
}
|
|
1143
|
+
function getIdentityTileIndices(viewport, z, tileSize, extent, modelMatrixInverse) {
|
|
1144
|
+
const bbox = getBoundingBox(viewport, null, extent);
|
|
1145
|
+
const scale = getScale(z, tileSize);
|
|
1146
|
+
const [minX, minY, maxX, maxY] = getIndexingCoords(bbox, scale, modelMatrixInverse);
|
|
1147
|
+
const indices = [];
|
|
1148
|
+
for (let x = Math.floor(minX); x < maxX; x++) {
|
|
1149
|
+
for (let y = Math.floor(minY); y < maxY; y++) {
|
|
1150
|
+
indices.push({ x, y, z });
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return indices;
|
|
1154
|
+
}
|
|
1155
|
+
function getTileZoomForViewport(viewport, tileSize, zoomOffset) {
|
|
1156
|
+
return viewport.isGeospatial ? Math.round(viewport.zoom + Math.log2(TILE_SIZE2 / tileSize)) + zoomOffset : Math.ceil(viewport.zoom) + zoomOffset;
|
|
1157
|
+
}
|
|
1158
|
+
function applyZoomBounds(z, minZoom, maxZoom, extent) {
|
|
1159
|
+
if (typeof minZoom === "number" && Number.isFinite(minZoom) && z < minZoom) {
|
|
1160
|
+
if (!extent) {
|
|
1161
|
+
return null;
|
|
1162
|
+
}
|
|
1163
|
+
z = minZoom;
|
|
1164
|
+
}
|
|
1165
|
+
if (typeof maxZoom === "number" && Number.isFinite(maxZoom) && z > maxZoom) {
|
|
1166
|
+
z = maxZoom;
|
|
1167
|
+
}
|
|
1168
|
+
return z;
|
|
1169
|
+
}
|
|
1170
|
+
function getDeckTileIndices(context) {
|
|
1171
|
+
const { viewState: viewport, maxZoom, minZoom, zRange = null, extent, tileSize = TILE_SIZE2, modelMatrix, modelMatrixInverse, zoomOffset = 0 } = context;
|
|
1172
|
+
let z = getTileZoomForViewport(viewport, tileSize, zoomOffset);
|
|
1173
|
+
z = applyZoomBounds(z, minZoom, maxZoom, extent);
|
|
1174
|
+
if (z === null) {
|
|
1175
|
+
return [];
|
|
1176
|
+
}
|
|
1177
|
+
let transformedExtent = extent || void 0;
|
|
1178
|
+
if (modelMatrix && modelMatrixInverse && extent && !viewport.isGeospatial) {
|
|
1179
|
+
transformedExtent = transformBox(extent, modelMatrix);
|
|
1180
|
+
}
|
|
1181
|
+
return viewport.isGeospatial ? getOSMTileIndices(viewport, z, zRange, extent || void 0) : getIdentityTileIndices(viewport, z, tileSize, transformedExtent || DEFAULT_EXTENT, modelMatrixInverse);
|
|
1182
|
+
}
|
|
1183
|
+
function getDeckTileBoundingBox(context, index) {
|
|
1184
|
+
return tileToBoundingBox(context.viewState, index.x, index.y, index.z, context.tileSize);
|
|
1185
|
+
}
|
|
1186
|
+
var sharedTile2DDeckAdapter = {
|
|
1187
|
+
getTileIndices: getDeckTileIndices,
|
|
1188
|
+
getTileBoundingBox: getDeckTileBoundingBox
|
|
1189
|
+
};
|
|
1190
|
+
|
|
1191
|
+
// dist/shared-tile-2d-layer/shared-tile-2d-view.js
|
|
1192
|
+
var TILE_STATE_VISITED = 1;
|
|
1193
|
+
var TILE_STATE_VISIBLE = 2;
|
|
1194
|
+
var STRATEGIES = {
|
|
1195
|
+
[STRATEGY_DEFAULT]: updateTileStateDefault,
|
|
1196
|
+
[STRATEGY_REPLACE]: updateTileStateReplace,
|
|
1197
|
+
[STRATEGY_NEVER]: () => {
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1200
|
+
var SharedTile2DView = class {
|
|
1201
|
+
/** Unique consumer identifier used by the shared tileset cache. */
|
|
1202
|
+
id = Symbol("tile-2d-view");
|
|
1203
|
+
/** Shared tileset queried by this view. */
|
|
1204
|
+
_tileset;
|
|
1205
|
+
/** Tiles selected during the latest traversal. */
|
|
1206
|
+
_selectedTiles = null;
|
|
1207
|
+
/** Incremented whenever this view's visible tile set changes. */
|
|
1208
|
+
_frameNumber = 0;
|
|
1209
|
+
/** Last viewport used to compute tile selection. */
|
|
1210
|
+
_viewport = null;
|
|
1211
|
+
/** Last z-range used during tile selection. */
|
|
1212
|
+
_zRange = null;
|
|
1213
|
+
/** Last model matrix applied to tile selection. */
|
|
1214
|
+
_modelMatrix = new import_core3.Matrix4();
|
|
1215
|
+
/** Inverse of the current model matrix. */
|
|
1216
|
+
_modelMatrixInverse = new import_core3.Matrix4();
|
|
1217
|
+
/** Per-tile visibility and selection flags for this view. */
|
|
1218
|
+
_state = /* @__PURE__ */ new Map();
|
|
1219
|
+
/** Creates a viewport-specific view of a shared tileset. */
|
|
1220
|
+
constructor(tileset) {
|
|
1221
|
+
this._tileset = tileset;
|
|
1222
|
+
if (!this._tileset.adapter) {
|
|
1223
|
+
this._tileset.setOptions({ adapter: sharedTile2DDeckAdapter });
|
|
1224
|
+
}
|
|
1225
|
+
this._tileset.attachConsumer(this.id);
|
|
1226
|
+
}
|
|
1227
|
+
/** Releases this view and detaches it from the shared tileset. */
|
|
1228
|
+
finalize() {
|
|
1229
|
+
this._tileset.detachConsumer(this.id);
|
|
1230
|
+
this._selectedTiles = null;
|
|
1231
|
+
this._state.clear();
|
|
1232
|
+
}
|
|
1233
|
+
/** Tiles selected for the last viewport update. */
|
|
1234
|
+
get selectedTiles() {
|
|
1235
|
+
return this._selectedTiles;
|
|
1236
|
+
}
|
|
1237
|
+
/** Indicates whether all selected tiles are fully loaded for this view. */
|
|
1238
|
+
get isLoaded() {
|
|
1239
|
+
return this._selectedTiles !== null && this._selectedTiles.every((tile) => tile.isLoaded);
|
|
1240
|
+
}
|
|
1241
|
+
/** Indicates whether any selected tile needs to be re-requested. */
|
|
1242
|
+
get needsReload() {
|
|
1243
|
+
return this._selectedTiles !== null && this._selectedTiles.some((tile) => tile.needsReload);
|
|
1244
|
+
}
|
|
1245
|
+
/** Updates tile selection and visibility for a viewport and returns the current frame number. */
|
|
1246
|
+
update(viewport, { zRange, modelMatrix } = { zRange: null, modelMatrix: null }) {
|
|
1247
|
+
const modelMatrixAsMatrix4 = modelMatrix ? new import_core3.Matrix4(modelMatrix) : new import_core3.Matrix4();
|
|
1248
|
+
const isModelMatrixNew = !modelMatrixAsMatrix4.equals(this._modelMatrix);
|
|
1249
|
+
if (!this._viewport || !viewport.equals(this._viewport) || !(0, import_core3.equals)(this._zRange, zRange) || isModelMatrixNew) {
|
|
1250
|
+
if (isModelMatrixNew) {
|
|
1251
|
+
this._modelMatrixInverse = modelMatrixAsMatrix4.clone().invert();
|
|
1252
|
+
this._modelMatrix = modelMatrixAsMatrix4;
|
|
1253
|
+
}
|
|
1254
|
+
this._viewport = viewport;
|
|
1255
|
+
this._zRange = zRange;
|
|
1256
|
+
const tileIndices = this._tileset.getTileIndices({
|
|
1257
|
+
viewState: viewport,
|
|
1258
|
+
maxZoom: this._tileset.maxZoom,
|
|
1259
|
+
minZoom: this._tileset.minZoom,
|
|
1260
|
+
zRange,
|
|
1261
|
+
modelMatrix: this._modelMatrix,
|
|
1262
|
+
modelMatrixInverse: this._modelMatrixInverse
|
|
1263
|
+
});
|
|
1264
|
+
this._selectedTiles = tileIndices.map((index) => this._tileset.getTile(index, true));
|
|
1265
|
+
this._tileset.prepareTiles();
|
|
1266
|
+
} else if (this.needsReload) {
|
|
1267
|
+
this._selectedTiles = (this._selectedTiles || []).map((tile) => this._tileset.getTile(tile.index, true));
|
|
1268
|
+
this._tileset.prepareTiles();
|
|
1269
|
+
}
|
|
1270
|
+
const changed = this._updateTileStates();
|
|
1271
|
+
this._tileset.updateConsumer(this.id, this._selectedTiles || [], this._getVisibleTiles());
|
|
1272
|
+
if (changed) {
|
|
1273
|
+
this._frameNumber++;
|
|
1274
|
+
}
|
|
1275
|
+
return this._frameNumber;
|
|
1276
|
+
}
|
|
1277
|
+
/** Tests whether a tile should render in the current viewport and culling rectangle. */
|
|
1278
|
+
isTileVisible(tile, cullRect, modelMatrix) {
|
|
1279
|
+
const state = this._state.get(tile);
|
|
1280
|
+
if (!(state == null ? void 0 : state.isVisible)) {
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
if (!cullRect || !this._viewport) {
|
|
1284
|
+
return true;
|
|
1285
|
+
}
|
|
1286
|
+
const boundsArr = this._getCullBounds({
|
|
1287
|
+
viewport: this._viewport,
|
|
1288
|
+
z: this._zRange,
|
|
1289
|
+
cullRect
|
|
1290
|
+
});
|
|
1291
|
+
return boundsArr.some((bounds) => this._tileOverlapsBounds(tile, bounds, modelMatrix));
|
|
1292
|
+
}
|
|
1293
|
+
/** Collects tiles currently marked visible for this view. */
|
|
1294
|
+
_getVisibleTiles() {
|
|
1295
|
+
var _a;
|
|
1296
|
+
const result = [];
|
|
1297
|
+
for (const tile of this._tileset.tiles) {
|
|
1298
|
+
if ((_a = this._state.get(tile)) == null ? void 0 : _a.isVisible) {
|
|
1299
|
+
result.push(tile);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
return result;
|
|
1303
|
+
}
|
|
1304
|
+
/** Memoized screen-space culling bounds helper. */
|
|
1305
|
+
_getCullBounds = memoize(getCullBounds);
|
|
1306
|
+
/** Recomputes selected and placeholder-visible tiles for the current view. */
|
|
1307
|
+
_updateTileStates() {
|
|
1308
|
+
const refinementStrategy = this._tileset.refinementStrategy || STRATEGY_DEFAULT;
|
|
1309
|
+
const allTiles = this._tileset.tiles;
|
|
1310
|
+
const previousVisibility = /* @__PURE__ */ new Map();
|
|
1311
|
+
for (const tile of allTiles) {
|
|
1312
|
+
const existing = this._state.get(tile);
|
|
1313
|
+
previousVisibility.set(tile, (existing == null ? void 0 : existing.isVisible) || false);
|
|
1314
|
+
this._state.set(tile, { isSelected: false, isVisible: false, state: 0 });
|
|
1315
|
+
}
|
|
1316
|
+
for (const tile of this._selectedTiles || []) {
|
|
1317
|
+
const state = this._state.get(tile) || { isSelected: false, isVisible: false, state: 0 };
|
|
1318
|
+
state.isSelected = true;
|
|
1319
|
+
state.isVisible = true;
|
|
1320
|
+
this._state.set(tile, state);
|
|
1321
|
+
}
|
|
1322
|
+
if (typeof refinementStrategy === "function") {
|
|
1323
|
+
refinementStrategy(allTiles);
|
|
1324
|
+
} else {
|
|
1325
|
+
STRATEGIES[refinementStrategy](allTiles, this._state);
|
|
1326
|
+
}
|
|
1327
|
+
let changed = false;
|
|
1328
|
+
for (const tile of allTiles) {
|
|
1329
|
+
const state = this._state.get(tile);
|
|
1330
|
+
if (state && state.isVisible !== previousVisibility.get(tile)) {
|
|
1331
|
+
changed = true;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
return changed;
|
|
1335
|
+
}
|
|
1336
|
+
/** Tests one tile against one culling bounds rectangle. */
|
|
1337
|
+
_tileOverlapsBounds(tile, [minX, minY, maxX, maxY], modelMatrix) {
|
|
1338
|
+
const bbox = this._getTileBoundingBox(tile, modelMatrix);
|
|
1339
|
+
if ("west" in bbox) {
|
|
1340
|
+
return bbox.west < maxX && bbox.east > minX && bbox.south < maxY && bbox.north > minY;
|
|
1341
|
+
}
|
|
1342
|
+
const y0 = Math.min(bbox.top, bbox.bottom);
|
|
1343
|
+
const y1 = Math.max(bbox.top, bbox.bottom);
|
|
1344
|
+
return bbox.left < maxX && bbox.right > minX && y0 < maxY && y1 > minY;
|
|
1345
|
+
}
|
|
1346
|
+
/** Applies model-matrix transforms to non-geospatial tile bounds when needed. */
|
|
1347
|
+
_getTileBoundingBox(tile, modelMatrix) {
|
|
1348
|
+
const { bbox } = tile;
|
|
1349
|
+
if ("west" in bbox || !modelMatrix || import_core3.Matrix4.IDENTITY.equals(modelMatrix)) {
|
|
1350
|
+
return bbox;
|
|
1351
|
+
}
|
|
1352
|
+
const [left, top, right, bottom] = transformBox([bbox.left, bbox.top, bbox.right, bbox.bottom], modelMatrix);
|
|
1353
|
+
return { left, top, right, bottom };
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
function updateTileStateDefault(allTiles, stateMap) {
|
|
1357
|
+
for (const tile of allTiles) {
|
|
1358
|
+
getTileState(stateMap, tile).state = 0;
|
|
1359
|
+
}
|
|
1360
|
+
for (const tile of allTiles) {
|
|
1361
|
+
if (getTileState(stateMap, tile).isSelected && !getPlaceholderInAncestors(tile, stateMap)) {
|
|
1362
|
+
getPlaceholderInChildren(tile, stateMap);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
for (const tile of allTiles) {
|
|
1366
|
+
const state = getTileState(stateMap, tile);
|
|
1367
|
+
state.isVisible = Boolean(state.state & TILE_STATE_VISIBLE);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
function updateTileStateReplace(allTiles, stateMap) {
|
|
1371
|
+
for (const tile of allTiles) {
|
|
1372
|
+
getTileState(stateMap, tile).state = 0;
|
|
1373
|
+
}
|
|
1374
|
+
for (const tile of allTiles) {
|
|
1375
|
+
if (getTileState(stateMap, tile).isSelected) {
|
|
1376
|
+
getPlaceholderInAncestors(tile, stateMap);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const sortedTiles = Array.from(allTiles).sort((t1, t2) => t1.zoom - t2.zoom);
|
|
1380
|
+
for (const tile of sortedTiles) {
|
|
1381
|
+
const tileState = getTileState(stateMap, tile);
|
|
1382
|
+
tileState.isVisible = Boolean(tileState.state & TILE_STATE_VISIBLE);
|
|
1383
|
+
if (tile.children && (tileState.isVisible || tileState.state & TILE_STATE_VISITED)) {
|
|
1384
|
+
for (const child of tile.children) {
|
|
1385
|
+
getTileState(stateMap, child).state = TILE_STATE_VISITED;
|
|
1386
|
+
}
|
|
1387
|
+
} else if (tileState.isSelected) {
|
|
1388
|
+
getPlaceholderInChildren(tile, stateMap);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
function getPlaceholderInAncestors(startTile, stateMap) {
|
|
1393
|
+
let tile = startTile;
|
|
1394
|
+
while (tile = tile.parent) {
|
|
1395
|
+
const state = getTileState(stateMap, tile);
|
|
1396
|
+
state.state |= TILE_STATE_VISIBLE | TILE_STATE_VISITED;
|
|
1397
|
+
if (tile.isLoaded || tile.content) {
|
|
1398
|
+
return true;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
function getPlaceholderInChildren(tile, stateMap) {
|
|
1404
|
+
const state = getTileState(stateMap, tile);
|
|
1405
|
+
state.state |= TILE_STATE_VISIBLE | TILE_STATE_VISITED;
|
|
1406
|
+
if (!tile.children || !tile.children.length || tile.isLoaded || tile.content) {
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
for (const child of tile.children) {
|
|
1410
|
+
const childState = getTileState(stateMap, child);
|
|
1411
|
+
if (!(childState.state & TILE_STATE_VISITED)) {
|
|
1412
|
+
getPlaceholderInChildren(child, stateMap);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
function getTileState(stateMap, tile) {
|
|
1417
|
+
let tileState = stateMap.get(tile);
|
|
1418
|
+
if (!tileState) {
|
|
1419
|
+
tileState = { isSelected: false, isVisible: false, state: 0 };
|
|
1420
|
+
stateMap.set(tile, tileState);
|
|
1421
|
+
}
|
|
1422
|
+
return tileState;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// dist/shared-tile-2d-layer/url-template.js
|
|
1426
|
+
function stringHash(s) {
|
|
1427
|
+
return Math.abs(s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0));
|
|
1428
|
+
}
|
|
1429
|
+
function getURLFromTemplate(template, tile) {
|
|
1430
|
+
if (!template || !template.length) {
|
|
1431
|
+
return null;
|
|
1432
|
+
}
|
|
1433
|
+
const { index, id } = tile;
|
|
1434
|
+
if (Array.isArray(template)) {
|
|
1435
|
+
template = template[stringHash(id) % template.length];
|
|
1436
|
+
}
|
|
1437
|
+
let url = template;
|
|
1438
|
+
for (const key of Object.keys(index)) {
|
|
1439
|
+
url = url.replace(new RegExp(`{${key}}`, "g"), String(index[key]));
|
|
1440
|
+
}
|
|
1441
|
+
if (Number.isInteger(index.y) && Number.isInteger(index.z)) {
|
|
1442
|
+
url = url.replace(/\{-y\}/g, String(Math.pow(2, index.z) - index.y - 1));
|
|
1443
|
+
}
|
|
1444
|
+
return url;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// dist/shared-tile-2d-layer/shared-tile-2d-layer.js
|
|
1448
|
+
function isTileSource(value) {
|
|
1449
|
+
return Boolean(value && typeof value === "object" && "getTileData" in value && typeof value.getTileData === "function" && "getMetadata" in value && typeof value.getMetadata === "function");
|
|
1450
|
+
}
|
|
1451
|
+
function isURLTemplate(value) {
|
|
1452
|
+
return value === null || typeof value === "string" || Array.isArray(value) && value.every((url) => typeof url === "string");
|
|
1453
|
+
}
|
|
1454
|
+
var tile2DDataType = {
|
|
1455
|
+
type: "object",
|
|
1456
|
+
value: null,
|
|
1457
|
+
validate: (value, propType) => propType.optional && value === null || value instanceof SharedTileset2D || isTileSource(value) || isURLTemplate(value),
|
|
1458
|
+
equal: (value1, value2) => value1 === value2
|
|
1459
|
+
};
|
|
1460
|
+
var defaultProps = {
|
|
1461
|
+
TilesetClass: SharedTileset2D,
|
|
1462
|
+
data: tile2DDataType,
|
|
1463
|
+
dataComparator: tile2DDataType.equal,
|
|
1464
|
+
renderSubLayers: { type: "function", value: (props) => new import_layers2.GeoJsonLayer(props) },
|
|
1465
|
+
getTileData: { type: "function", optional: true, value: null },
|
|
1466
|
+
onViewportLoad: { type: "function", optional: true, value: null },
|
|
1467
|
+
onTileLoad: { type: "function", value: () => {
|
|
1468
|
+
} },
|
|
1469
|
+
onTileUnload: { type: "function", value: () => {
|
|
1470
|
+
} },
|
|
1471
|
+
onTileError: { type: "function", value: () => {
|
|
1472
|
+
} },
|
|
1473
|
+
extent: { type: "array", optional: true, value: null, compare: true },
|
|
1474
|
+
tileSize: 512,
|
|
1475
|
+
maxZoom: null,
|
|
1476
|
+
minZoom: 0,
|
|
1477
|
+
maxCacheSize: null,
|
|
1478
|
+
maxCacheByteSize: null,
|
|
1479
|
+
refinementStrategy: STRATEGY_DEFAULT,
|
|
1480
|
+
zRange: null,
|
|
1481
|
+
maxRequests: 6,
|
|
1482
|
+
debounceTime: 0,
|
|
1483
|
+
zoomOffset: 0
|
|
1484
|
+
};
|
|
1485
|
+
var TILE2D_LAYER_DEFAULT_OPTION_VALUES = {
|
|
1486
|
+
maxCacheSize: null,
|
|
1487
|
+
maxCacheByteSize: null,
|
|
1488
|
+
maxZoom: null,
|
|
1489
|
+
minZoom: 0,
|
|
1490
|
+
tileSize: 512,
|
|
1491
|
+
refinementStrategy: STRATEGY_DEFAULT,
|
|
1492
|
+
extent: null,
|
|
1493
|
+
maxRequests: 6,
|
|
1494
|
+
debounceTime: 0,
|
|
1495
|
+
zoomOffset: 0
|
|
1496
|
+
};
|
|
1497
|
+
var SharedTile2DLayer = class extends import_core4.CompositeLayer {
|
|
1498
|
+
/** Viewports currently known to this layer during multi-view rendering. */
|
|
1499
|
+
_knownViewports = /* @__PURE__ */ new Map();
|
|
1500
|
+
/** Internal layer state shared across render passes. */
|
|
1501
|
+
state = null;
|
|
1502
|
+
/** Initializes layer-owned tileset state. */
|
|
1503
|
+
initializeState() {
|
|
1504
|
+
this._knownViewports.clear();
|
|
1505
|
+
if (this.context.viewport) {
|
|
1506
|
+
this._knownViewports.set(this.context.viewport.id || "default", this.context.viewport);
|
|
1507
|
+
}
|
|
1508
|
+
this.state = {
|
|
1509
|
+
tileset: null,
|
|
1510
|
+
tilesetViews: /* @__PURE__ */ new Map(),
|
|
1511
|
+
ownsTileset: false,
|
|
1512
|
+
isLoaded: false,
|
|
1513
|
+
frameNumbers: /* @__PURE__ */ new Map(),
|
|
1514
|
+
tileLayers: /* @__PURE__ */ new Map(),
|
|
1515
|
+
unsubscribeTilesetEvents: null
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
/** Finalizes owned resources and detaches from any shared tileset. */
|
|
1519
|
+
finalizeState() {
|
|
1520
|
+
var _a, _b, _c;
|
|
1521
|
+
(_b = (_a = this.state).unsubscribeTilesetEvents) == null ? void 0 : _b.call(_a);
|
|
1522
|
+
for (const tilesetView of this.state.tilesetViews.values()) {
|
|
1523
|
+
tilesetView.finalize();
|
|
1524
|
+
}
|
|
1525
|
+
if (this.state.ownsTileset) {
|
|
1526
|
+
(_c = this.state.tileset) == null ? void 0 : _c.finalize();
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
/** Returns whether all visible sub-layers for all tracked views are loaded. */
|
|
1530
|
+
get isLoaded() {
|
|
1531
|
+
const { tilesetViews, tileLayers } = this.state;
|
|
1532
|
+
if (!tilesetViews.size) {
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
1535
|
+
return Boolean(Array.from(tilesetViews.values()).every((tilesetView) => {
|
|
1536
|
+
var _a;
|
|
1537
|
+
return (_a = tilesetView.selectedTiles) == null ? void 0 : _a.every((tile) => {
|
|
1538
|
+
const cachedLayers = tileLayers.get(tile.id);
|
|
1539
|
+
return tile.isLoaded && (!tile.content || !cachedLayers || cachedLayers.every((layer) => layer.isLoaded));
|
|
1540
|
+
});
|
|
1541
|
+
}));
|
|
1542
|
+
}
|
|
1543
|
+
/** Triggers updates whenever props, data, or update triggers change. */
|
|
1544
|
+
shouldUpdateState({ changeFlags }) {
|
|
1545
|
+
return changeFlags.somethingChanged;
|
|
1546
|
+
}
|
|
1547
|
+
/** Creates, reuses, or reconfigures the backing shared tileset and per-view state. */
|
|
1548
|
+
updateState({ changeFlags }) {
|
|
1549
|
+
if (this.context.viewport) {
|
|
1550
|
+
this._knownViewports.set(this._getViewportKey(), this.context.viewport);
|
|
1551
|
+
}
|
|
1552
|
+
const propsChanged = Boolean(changeFlags.propsOrDataChanged || changeFlags.updateTriggersChanged);
|
|
1553
|
+
const dataChanged = changeFlags.dataChanged || changeFlags.updateTriggersChanged && (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getTileData);
|
|
1554
|
+
let { tileset, ownsTileset } = this.state;
|
|
1555
|
+
const nextExternalTileset = this.props.data instanceof SharedTileset2D ? this.props.data : null;
|
|
1556
|
+
if (nextExternalTileset && !nextExternalTileset.adapter) {
|
|
1557
|
+
nextExternalTileset.setOptions({ adapter: sharedTile2DDeckAdapter });
|
|
1558
|
+
}
|
|
1559
|
+
const nextOwnsTileset = !nextExternalTileset;
|
|
1560
|
+
const nextTileset = this._resolveTileset(tileset, ownsTileset, nextExternalTileset);
|
|
1561
|
+
const tilesetChanged = nextTileset !== tileset || nextOwnsTileset !== ownsTileset;
|
|
1562
|
+
if (tilesetChanged) {
|
|
1563
|
+
this._releaseTileset(tileset, ownsTileset);
|
|
1564
|
+
tileset = nextTileset;
|
|
1565
|
+
ownsTileset = nextOwnsTileset;
|
|
1566
|
+
this.setState({
|
|
1567
|
+
tileset,
|
|
1568
|
+
tilesetViews: /* @__PURE__ */ new Map(),
|
|
1569
|
+
ownsTileset,
|
|
1570
|
+
tileLayers: /* @__PURE__ */ new Map(),
|
|
1571
|
+
frameNumbers: /* @__PURE__ */ new Map(),
|
|
1572
|
+
unsubscribeTilesetEvents: nextTileset.subscribe({
|
|
1573
|
+
onTileLoad: this._onTileLoad.bind(this),
|
|
1574
|
+
onTileError: this._onTileError.bind(this),
|
|
1575
|
+
onTileUnload: this._onTileUnload.bind(this),
|
|
1576
|
+
onUpdate: () => this.setNeedsUpdate(),
|
|
1577
|
+
onError: (error) => this.raiseError(error, "loading TileSource metadata")
|
|
1578
|
+
})
|
|
1579
|
+
});
|
|
1580
|
+
} else {
|
|
1581
|
+
this._updateExistingTileset(propsChanged, ownsTileset, Boolean(dataChanged), nextTileset);
|
|
1582
|
+
}
|
|
1583
|
+
this._updateTileset();
|
|
1584
|
+
}
|
|
1585
|
+
/** Resolves whether to reuse a shared tileset, reuse an owned tileset, or create a new one. */
|
|
1586
|
+
_resolveTileset(currentTileset, ownsCurrentTileset, nextExternalTileset) {
|
|
1587
|
+
if (nextExternalTileset) {
|
|
1588
|
+
return nextExternalTileset;
|
|
1589
|
+
}
|
|
1590
|
+
if (currentTileset && ownsCurrentTileset) {
|
|
1591
|
+
return currentTileset;
|
|
1592
|
+
}
|
|
1593
|
+
return new this.props.TilesetClass(this._getTilesetOptions());
|
|
1594
|
+
}
|
|
1595
|
+
/** Tears down subscriptions and per-view state for the outgoing tileset. */
|
|
1596
|
+
_releaseTileset(tileset, ownsTileset) {
|
|
1597
|
+
var _a, _b;
|
|
1598
|
+
(_b = (_a = this.state).unsubscribeTilesetEvents) == null ? void 0 : _b.call(_a);
|
|
1599
|
+
for (const tilesetView of this.state.tilesetViews.values()) {
|
|
1600
|
+
tilesetView.finalize();
|
|
1601
|
+
}
|
|
1602
|
+
if (ownsTileset) {
|
|
1603
|
+
tileset == null ? void 0 : tileset.finalize();
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
/** Applies prop updates to an existing tileset without replacing it. */
|
|
1607
|
+
_updateExistingTileset(propsChanged, ownsTileset, dataChanged, tileset) {
|
|
1608
|
+
if (!propsChanged) {
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
if (ownsTileset) {
|
|
1612
|
+
tileset.setOptions(this._getTilesetOptions());
|
|
1613
|
+
if (dataChanged) {
|
|
1614
|
+
tileset.reloadAll();
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
this.state.tileLayers.clear();
|
|
1619
|
+
}
|
|
1620
|
+
/** Resolves the current tileset configuration from layer props. */
|
|
1621
|
+
_getTilesetOptions() {
|
|
1622
|
+
const { tileSize, maxCacheSize, maxCacheByteSize, refinementStrategy, extent, maxZoom, minZoom, maxRequests, debounceTime, zoomOffset } = this.props;
|
|
1623
|
+
const tileSource = isTileSource(this.props.data) ? this.props.data : void 0;
|
|
1624
|
+
const options = {
|
|
1625
|
+
tileSource,
|
|
1626
|
+
adapter: sharedTile2DDeckAdapter,
|
|
1627
|
+
getTileData: tileSource ? void 0 : this.getTileData.bind(this),
|
|
1628
|
+
onTileLoad: () => {
|
|
1629
|
+
},
|
|
1630
|
+
onTileError: () => {
|
|
1631
|
+
},
|
|
1632
|
+
onTileUnload: () => {
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
this._assignTilesetOptionIfExplicit(options, "maxCacheSize", maxCacheSize, TILE2D_LAYER_DEFAULT_OPTION_VALUES.maxCacheSize);
|
|
1636
|
+
this._assignTilesetOptionIfExplicit(options, "maxCacheByteSize", maxCacheByteSize, TILE2D_LAYER_DEFAULT_OPTION_VALUES.maxCacheByteSize);
|
|
1637
|
+
this._assignTilesetOptionIfExplicit(options, "maxZoom", maxZoom, TILE2D_LAYER_DEFAULT_OPTION_VALUES.maxZoom);
|
|
1638
|
+
this._assignTilesetOptionIfExplicit(options, "minZoom", minZoom, TILE2D_LAYER_DEFAULT_OPTION_VALUES.minZoom);
|
|
1639
|
+
this._assignTilesetOptionIfExplicit(options, "tileSize", tileSize, TILE2D_LAYER_DEFAULT_OPTION_VALUES.tileSize);
|
|
1640
|
+
this._assignTilesetOptionIfExplicit(options, "refinementStrategy", refinementStrategy, TILE2D_LAYER_DEFAULT_OPTION_VALUES.refinementStrategy);
|
|
1641
|
+
this._assignTilesetOptionIfExplicit(options, "extent", extent, TILE2D_LAYER_DEFAULT_OPTION_VALUES.extent);
|
|
1642
|
+
this._assignTilesetOptionIfExplicit(options, "maxRequests", maxRequests, TILE2D_LAYER_DEFAULT_OPTION_VALUES.maxRequests);
|
|
1643
|
+
this._assignTilesetOptionIfExplicit(options, "debounceTime", debounceTime, TILE2D_LAYER_DEFAULT_OPTION_VALUES.debounceTime);
|
|
1644
|
+
this._assignTilesetOptionIfExplicit(options, "zoomOffset", zoomOffset, TILE2D_LAYER_DEFAULT_OPTION_VALUES.zoomOffset);
|
|
1645
|
+
return options;
|
|
1646
|
+
}
|
|
1647
|
+
/** Updates per-view traversal state for all known viewports. */
|
|
1648
|
+
_updateTileset() {
|
|
1649
|
+
const { zRange, modelMatrix } = this.props;
|
|
1650
|
+
let anyTilesetChanged = false;
|
|
1651
|
+
for (const [viewportKey, viewport] of this._knownViewports) {
|
|
1652
|
+
this._prunePlaceholderViewportView(viewportKey);
|
|
1653
|
+
const tilesetView = this._getOrCreateTilesetView(viewportKey);
|
|
1654
|
+
const frameNumber = tilesetView.update(viewport, { zRange, modelMatrix });
|
|
1655
|
+
const previousFrameNumber = this.state.frameNumbers.get(viewportKey);
|
|
1656
|
+
const tilesetChanged = previousFrameNumber !== frameNumber;
|
|
1657
|
+
anyTilesetChanged ||= tilesetChanged;
|
|
1658
|
+
if (tilesetView.isLoaded && tilesetChanged) {
|
|
1659
|
+
this._onViewportLoad(tilesetView);
|
|
1660
|
+
}
|
|
1661
|
+
if (tilesetChanged) {
|
|
1662
|
+
this.state.frameNumbers.set(viewportKey, frameNumber);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
const nextIsLoaded = this.isLoaded;
|
|
1666
|
+
const loadingStateChanged = this.state.isLoaded !== nextIsLoaded;
|
|
1667
|
+
if (loadingStateChanged) {
|
|
1668
|
+
for (const tilesetView of this.state.tilesetViews.values()) {
|
|
1669
|
+
if (tilesetView.isLoaded) {
|
|
1670
|
+
this._onViewportLoad(tilesetView);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
if (anyTilesetChanged) {
|
|
1675
|
+
this.setState({ frameNumbers: new Map(this.state.frameNumbers) });
|
|
1676
|
+
}
|
|
1677
|
+
this.state.isLoaded = nextIsLoaded;
|
|
1678
|
+
}
|
|
1679
|
+
/** Emits the viewport-load callback for one view. */
|
|
1680
|
+
_onViewportLoad(tilesetView) {
|
|
1681
|
+
var _a, _b;
|
|
1682
|
+
if (tilesetView.selectedTiles) {
|
|
1683
|
+
(_b = (_a = this.props).onViewportLoad) == null ? void 0 : _b.call(_a, tilesetView.selectedTiles);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
/** Clears cached sub-layers when a tile loads. */
|
|
1687
|
+
_onTileLoad(tile) {
|
|
1688
|
+
this.state.tileLayers.delete(tile.id);
|
|
1689
|
+
this.props.onTileLoad(tile);
|
|
1690
|
+
this.setNeedsUpdate();
|
|
1691
|
+
}
|
|
1692
|
+
/** Clears cached sub-layers when a tile errors. */
|
|
1693
|
+
_onTileError(error, tile) {
|
|
1694
|
+
this.state.tileLayers.delete(tile.id);
|
|
1695
|
+
this.props.onTileError(error, tile);
|
|
1696
|
+
this.setNeedsUpdate();
|
|
1697
|
+
}
|
|
1698
|
+
/** Removes cached sub-layers when a tile is evicted. */
|
|
1699
|
+
_onTileUnload(tile) {
|
|
1700
|
+
this.state.tileLayers.delete(tile.id);
|
|
1701
|
+
this.props.onTileUnload(tile);
|
|
1702
|
+
}
|
|
1703
|
+
/** Calls the URL-template loader path for a tile when the layer owns the tileset. */
|
|
1704
|
+
getTileData(tile) {
|
|
1705
|
+
const { data, getTileData, fetch } = this.props;
|
|
1706
|
+
const { signal } = tile;
|
|
1707
|
+
if (!isURLTemplate(data)) {
|
|
1708
|
+
return null;
|
|
1709
|
+
}
|
|
1710
|
+
tile.url = getURLFromTemplate(data, tile);
|
|
1711
|
+
if (getTileData) {
|
|
1712
|
+
return getTileData(tile);
|
|
1713
|
+
}
|
|
1714
|
+
if (fetch && tile.url) {
|
|
1715
|
+
return fetch(tile.url, { propName: "data", layer: this, signal });
|
|
1716
|
+
}
|
|
1717
|
+
return null;
|
|
1718
|
+
}
|
|
1719
|
+
/** Default tile sub-layer renderer, delegating to `renderSubLayers`. */
|
|
1720
|
+
renderSubLayers(props) {
|
|
1721
|
+
return this.props.renderSubLayers(props);
|
|
1722
|
+
}
|
|
1723
|
+
/** Hook for subclasses to provide extra sub-layer props per tile. */
|
|
1724
|
+
getSubLayerPropsByTile(_tile) {
|
|
1725
|
+
return null;
|
|
1726
|
+
}
|
|
1727
|
+
/** Adds tile references to picking info returned from sub-layers. */
|
|
1728
|
+
getPickingInfo(params) {
|
|
1729
|
+
const { sourceLayer } = params;
|
|
1730
|
+
if (!sourceLayer) {
|
|
1731
|
+
throw new Error("SharedTile2DLayer picking info requires a source layer.");
|
|
1732
|
+
}
|
|
1733
|
+
const sourceTile = sourceLayer.props.tile;
|
|
1734
|
+
const info = params.info;
|
|
1735
|
+
if (info.picked) {
|
|
1736
|
+
info.tile = sourceTile;
|
|
1737
|
+
}
|
|
1738
|
+
info.sourceTile = sourceTile;
|
|
1739
|
+
info.sourceTileSubLayer = sourceLayer;
|
|
1740
|
+
return info;
|
|
1741
|
+
}
|
|
1742
|
+
/** Forwards auto-highlight updates to the picked sub-layer. */
|
|
1743
|
+
_updateAutoHighlight(info) {
|
|
1744
|
+
info.sourceTileSubLayer.updateAutoHighlight(info);
|
|
1745
|
+
}
|
|
1746
|
+
/** Renders cached or newly generated sub-layers for each loaded tile. */
|
|
1747
|
+
renderLayers() {
|
|
1748
|
+
const { tileset, tileLayers } = this.state;
|
|
1749
|
+
if (!tileset) {
|
|
1750
|
+
return null;
|
|
1751
|
+
}
|
|
1752
|
+
return tileset.tiles.map((tile) => {
|
|
1753
|
+
const subLayerProps = this.getSubLayerPropsByTile(tile);
|
|
1754
|
+
let layers = tileLayers.get(tile.id);
|
|
1755
|
+
if (!tile.isLoaded && !tile.content) {
|
|
1756
|
+
return layers;
|
|
1757
|
+
}
|
|
1758
|
+
if (!layers) {
|
|
1759
|
+
const rendered = this.renderSubLayers({
|
|
1760
|
+
...this.props,
|
|
1761
|
+
...this.getSubLayerProps({
|
|
1762
|
+
id: tile.id,
|
|
1763
|
+
updateTriggers: this.props.updateTriggers
|
|
1764
|
+
}),
|
|
1765
|
+
data: tile.content,
|
|
1766
|
+
_offset: 0,
|
|
1767
|
+
tile
|
|
1768
|
+
});
|
|
1769
|
+
layers = this._flattenTileLayers(rendered).map((layer) => layer.clone({ tile, ...subLayerProps }));
|
|
1770
|
+
tileLayers.set(tile.id, layers);
|
|
1771
|
+
} else if (subLayerProps && layers[0] && Object.keys(subLayerProps).some((propName) => layers[0].props[propName] !== subLayerProps[propName])) {
|
|
1772
|
+
layers = layers.map((layer) => layer.clone(subLayerProps));
|
|
1773
|
+
tileLayers.set(tile.id, layers);
|
|
1774
|
+
}
|
|
1775
|
+
return layers;
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
/** Filters tile sub-layers based on the active view-specific visibility state. */
|
|
1779
|
+
filterSubLayer({ layer, cullRect }) {
|
|
1780
|
+
const { tile } = layer.props;
|
|
1781
|
+
const tilesetView = this._getOrCreateTilesetView(this._getViewportKey());
|
|
1782
|
+
return tilesetView.isTileVisible(tile, cullRect, this.props.modelMatrix ? new import_core5.Matrix4(this.props.modelMatrix) : null);
|
|
1783
|
+
}
|
|
1784
|
+
/** Returns the active viewport key used to isolate per-view traversal state. */
|
|
1785
|
+
_getViewportKey() {
|
|
1786
|
+
var _a;
|
|
1787
|
+
return ((_a = this.context.viewport) == null ? void 0 : _a.id) || "default";
|
|
1788
|
+
}
|
|
1789
|
+
/** Copies a tileset option only when the layer prop was explicitly set. */
|
|
1790
|
+
_assignTilesetOptionIfExplicit(options, key, value, defaultValue) {
|
|
1791
|
+
if (!this._isDefaultOptionValue(value, defaultValue)) {
|
|
1792
|
+
options[key] = value;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
/** Tests whether a layer prop still has its default value. */
|
|
1796
|
+
_isDefaultOptionValue(value, defaultValue) {
|
|
1797
|
+
if (Array.isArray(value) || Array.isArray(defaultValue)) {
|
|
1798
|
+
return Array.isArray(value) && Array.isArray(defaultValue) && value.length === defaultValue.length && value.every((entry, index) => entry === defaultValue[index]);
|
|
1799
|
+
}
|
|
1800
|
+
return value === defaultValue;
|
|
1801
|
+
}
|
|
1802
|
+
/** Drops the bootstrap placeholder viewport after a real viewport is known. */
|
|
1803
|
+
_prunePlaceholderViewportView(viewportKey) {
|
|
1804
|
+
const placeholderViewportKey = "DEFAULT-INITIAL-VIEWPORT";
|
|
1805
|
+
if (viewportKey !== placeholderViewportKey) {
|
|
1806
|
+
const placeholderView = this.state.tilesetViews.get(placeholderViewportKey);
|
|
1807
|
+
if (placeholderView) {
|
|
1808
|
+
placeholderView.finalize();
|
|
1809
|
+
this.state.tilesetViews.delete(placeholderViewportKey);
|
|
1810
|
+
this.state.frameNumbers.delete(placeholderViewportKey);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
/** Returns the per-viewport traversal state, creating it on demand. */
|
|
1815
|
+
_getOrCreateTilesetView(viewportKey) {
|
|
1816
|
+
let tilesetView = this.state.tilesetViews.get(viewportKey);
|
|
1817
|
+
if (!tilesetView) {
|
|
1818
|
+
const tileset = this.state.tileset;
|
|
1819
|
+
if (!tileset) {
|
|
1820
|
+
throw new Error("SharedTile2DLayer tileset was not initialized.");
|
|
1821
|
+
}
|
|
1822
|
+
tilesetView = new SharedTile2DView(tileset);
|
|
1823
|
+
this.state.tilesetViews.set(viewportKey, tilesetView);
|
|
1824
|
+
}
|
|
1825
|
+
return tilesetView;
|
|
1826
|
+
}
|
|
1827
|
+
/** Registers additional viewports in multi-view rendering scenarios. */
|
|
1828
|
+
activateViewport(viewport) {
|
|
1829
|
+
const viewportKey = viewport.id || "default";
|
|
1830
|
+
const previousViewport = this._knownViewports.get(viewportKey);
|
|
1831
|
+
this._knownViewports.set(viewportKey, viewport);
|
|
1832
|
+
if (!previousViewport || !viewport.equals(previousViewport)) {
|
|
1833
|
+
this.setNeedsUpdate();
|
|
1834
|
+
}
|
|
1835
|
+
super.activateViewport(viewport);
|
|
1836
|
+
}
|
|
1837
|
+
/** Normalizes nested render output into a flat tile sub-layer array. */
|
|
1838
|
+
_flattenTileLayers(rendered) {
|
|
1839
|
+
return (0, import_core4._flatten)(rendered, Boolean);
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
/** Layer default props consumed by deck.gl prop management. */
|
|
1843
|
+
__publicField(SharedTile2DLayer, "defaultProps", defaultProps);
|
|
1844
|
+
/** Stable layer name used in logs and devtools. */
|
|
1845
|
+
__publicField(SharedTile2DLayer, "layerName", "SharedTile2DLayer");
|
|
1846
|
+
|
|
1847
|
+
// dist/tile-grid-layer/tile-grid-layer.js
|
|
1848
|
+
var import_core6 = require("@deck.gl/core");
|
|
1849
|
+
var import_layers3 = require("@deck.gl/layers");
|
|
1850
|
+
var defaultProps2 = {
|
|
1851
|
+
tile: { type: "object", value: void 0 },
|
|
1852
|
+
showBorder: true,
|
|
1853
|
+
showLabel: true,
|
|
1854
|
+
getLabel: {
|
|
1855
|
+
type: "function",
|
|
1856
|
+
value: (tile) => `z${tile.index.z} x${tile.index.x} y${tile.index.y}`
|
|
1857
|
+
},
|
|
1858
|
+
borderColor: [255, 255, 255, 180],
|
|
1859
|
+
labelColor: [255, 255, 255, 255],
|
|
1860
|
+
labelBackgroundColor: [15, 23, 42, 210],
|
|
1861
|
+
borderWidthMinPixels: 1,
|
|
1862
|
+
labelSize: 12
|
|
1863
|
+
};
|
|
1864
|
+
function getTilePath(bbox) {
|
|
1865
|
+
if ("west" in bbox) {
|
|
1866
|
+
return [
|
|
1867
|
+
[bbox.west, bbox.north],
|
|
1868
|
+
[bbox.west, bbox.south],
|
|
1869
|
+
[bbox.east, bbox.south],
|
|
1870
|
+
[bbox.east, bbox.north],
|
|
1871
|
+
[bbox.west, bbox.north]
|
|
1872
|
+
];
|
|
1873
|
+
}
|
|
1874
|
+
return [
|
|
1875
|
+
[bbox.left, bbox.top],
|
|
1876
|
+
[bbox.left, bbox.bottom],
|
|
1877
|
+
[bbox.right, bbox.bottom],
|
|
1878
|
+
[bbox.right, bbox.top],
|
|
1879
|
+
[bbox.left, bbox.top]
|
|
1880
|
+
];
|
|
1881
|
+
}
|
|
1882
|
+
function getTileCenter(bbox) {
|
|
1883
|
+
if ("west" in bbox) {
|
|
1884
|
+
return [(bbox.west + bbox.east) / 2, (bbox.north + bbox.south) / 2];
|
|
1885
|
+
}
|
|
1886
|
+
return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];
|
|
1887
|
+
}
|
|
1888
|
+
var TileGridLayer = class extends import_core6.CompositeLayer {
|
|
1889
|
+
/** Builds the tile border and label sublayers. */
|
|
1890
|
+
renderLayers() {
|
|
1891
|
+
const { tile, showBorder, showLabel, getLabel, borderColor, labelColor, labelBackgroundColor, borderWidthMinPixels, labelSize } = this.props;
|
|
1892
|
+
const item = {
|
|
1893
|
+
path: getTilePath(tile.bbox),
|
|
1894
|
+
center: getTileCenter(tile.bbox),
|
|
1895
|
+
label: typeof getLabel === "function" ? getLabel(tile) : getLabel
|
|
1896
|
+
};
|
|
1897
|
+
return [
|
|
1898
|
+
showBorder ? new import_layers3.PathLayer(this.getSubLayerProps({
|
|
1899
|
+
id: "border"
|
|
1900
|
+
}), {
|
|
1901
|
+
data: [item],
|
|
1902
|
+
getPath: (d) => d.path,
|
|
1903
|
+
getColor: borderColor,
|
|
1904
|
+
widthMinPixels: borderWidthMinPixels,
|
|
1905
|
+
pickable: false
|
|
1906
|
+
}) : null,
|
|
1907
|
+
showLabel ? new import_layers3.TextLayer(this.getSubLayerProps({
|
|
1908
|
+
id: "label"
|
|
1909
|
+
}), {
|
|
1910
|
+
data: [item],
|
|
1911
|
+
getPosition: (d) => d.center,
|
|
1912
|
+
getText: (d) => d.label,
|
|
1913
|
+
getColor: labelColor,
|
|
1914
|
+
getBackgroundColor: labelBackgroundColor,
|
|
1915
|
+
getSize: labelSize,
|
|
1916
|
+
sizeUnits: "pixels",
|
|
1917
|
+
background: true,
|
|
1918
|
+
getTextAnchor: "middle",
|
|
1919
|
+
getAlignmentBaseline: "center",
|
|
1920
|
+
pickable: false
|
|
1921
|
+
}) : null
|
|
1922
|
+
];
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
__publicField(TileGridLayer, "layerName", "TileGridLayer");
|
|
1926
|
+
__publicField(TileGridLayer, "defaultProps", defaultProps2);
|
|
1927
|
+
|
|
136
1928
|
// dist/global-grid-layer/global-grid-layer.js
|
|
137
1929
|
var import_geo_layers2 = require("@deck.gl/geo-layers");
|
|
138
1930
|
|
|
@@ -575,7 +2367,7 @@ function getGeohashBounds(geohash) {
|
|
|
575
2367
|
}
|
|
576
2368
|
|
|
577
2369
|
// dist/global-grid-systems/grids/quadkey-grid.js
|
|
578
|
-
var
|
|
2370
|
+
var TILE_SIZE3 = 512;
|
|
579
2371
|
var QuadkeyGrid = {
|
|
580
2372
|
name: "quadkey",
|
|
581
2373
|
hasNumericRepresentation: true,
|
|
@@ -614,7 +2406,7 @@ function quadkeyToWorldBounds(quadkey) {
|
|
|
614
2406
|
let x = 0;
|
|
615
2407
|
let y = 0;
|
|
616
2408
|
let mask = 1 << quadkey.length;
|
|
617
|
-
const scale = mask /
|
|
2409
|
+
const scale = mask / TILE_SIZE3;
|
|
618
2410
|
for (let i = 0; i < quadkey.length; i++) {
|
|
619
2411
|
mask >>= 1;
|
|
620
2412
|
const q = parseInt(quadkey[i], 10);
|
|
@@ -624,8 +2416,8 @@ function quadkeyToWorldBounds(quadkey) {
|
|
|
624
2416
|
y |= mask;
|
|
625
2417
|
}
|
|
626
2418
|
return [
|
|
627
|
-
[x / scale,
|
|
628
|
-
[(x + 0.99) / scale,
|
|
2419
|
+
[x / scale, TILE_SIZE3 - y / scale],
|
|
2420
|
+
[(x + 0.99) / scale, TILE_SIZE3 - (y + 0.99) / scale]
|
|
629
2421
|
];
|
|
630
2422
|
}
|
|
631
2423
|
var PI = Math.PI;
|
|
@@ -633,8 +2425,8 @@ var PI_4 = PI / 4;
|
|
|
633
2425
|
var RADIANS_TO_DEGREES = 180 / PI;
|
|
634
2426
|
function worldToLngLat(xy) {
|
|
635
2427
|
const [x, y] = xy;
|
|
636
|
-
const lambda2 = x /
|
|
637
|
-
const phi2 = 2 * (Math.atan(Math.exp(y /
|
|
2428
|
+
const lambda2 = x / TILE_SIZE3 * (2 * PI) - PI;
|
|
2429
|
+
const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE3 * (2 * PI) - PI)) - PI_4);
|
|
638
2430
|
return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
|
|
639
2431
|
}
|
|
640
2432
|
//# sourceMappingURL=index.cjs.map
|