2021-09-20 17:14:55 +02:00
|
|
|
import FilteredLayer from "../../../Models/FilteredLayer";
|
2021-09-21 02:10:42 +02:00
|
|
|
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
2021-09-20 17:14:55 +02:00
|
|
|
import {UIEventSource} from "../../UIEventSource";
|
|
|
|
import Loc from "../../../Models/Loc";
|
2021-09-21 02:10:42 +02:00
|
|
|
import TileHierarchy from "./TileHierarchy";
|
2021-09-26 17:36:39 +02:00
|
|
|
import {Tiles} from "../../../Models/TileRange";
|
2021-12-13 02:05:34 +01:00
|
|
|
import {BBox} from "../../BBox";
|
2021-09-20 17:14:55 +02:00
|
|
|
|
2021-09-21 02:10:42 +02:00
|
|
|
/***
|
|
|
|
* A tiled source which dynamically loads the required tiles at a fixed zoom level
|
|
|
|
*/
|
|
|
|
export default class DynamicTileSource implements TileHierarchy<FeatureSourceForLayer & Tiled> {
|
|
|
|
public readonly loadedTiles: Map<number, FeatureSourceForLayer & Tiled>;
|
2021-11-07 16:34:51 +01:00
|
|
|
private readonly _loadedTiles = new Set<number>();
|
2021-09-20 17:14:55 +02:00
|
|
|
|
|
|
|
constructor(
|
|
|
|
layer: FilteredLayer,
|
|
|
|
zoomlevel: number,
|
2021-09-21 02:10:42 +02:00
|
|
|
constructTile: (zxy: [number, number, number]) => (FeatureSourceForLayer & Tiled),
|
2021-09-20 17:14:55 +02:00
|
|
|
state: {
|
2021-12-13 02:05:34 +01:00
|
|
|
currentBounds: UIEventSource<BBox>;
|
2021-09-20 17:14:55 +02:00
|
|
|
locationControl: UIEventSource<Loc>
|
|
|
|
}
|
|
|
|
) {
|
|
|
|
const self = this;
|
2021-09-21 02:10:42 +02:00
|
|
|
|
2021-11-07 16:34:51 +01:00
|
|
|
this.loadedTiles = new Map<number, FeatureSourceForLayer & Tiled>()
|
2021-09-20 17:14:55 +02:00
|
|
|
const neededTiles = state.locationControl.map(
|
|
|
|
location => {
|
2022-02-07 01:59:07 +01:00
|
|
|
if (!layer.isDisplayed.data && !layer.layerDef.forceLoad) {
|
2021-09-20 17:14:55 +02:00
|
|
|
// No need to download! - the layer is disabled
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (location.zoom < layer.layerDef.minzoom) {
|
|
|
|
// No need to download! - the layer is disabled
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Yup, this is cheating to just get the bounds here
|
2021-12-13 02:05:34 +01:00
|
|
|
const bounds = state.currentBounds.data
|
2021-09-20 17:14:55 +02:00
|
|
|
if (bounds === undefined) {
|
|
|
|
// We'll retry later
|
|
|
|
return undefined
|
|
|
|
}
|
2021-09-26 17:36:39 +02:00
|
|
|
const tileRange = Tiles.TileRangeBetween(zoomlevel, bounds.getNorth(), bounds.getEast(), bounds.getSouth(), bounds.getWest())
|
2022-01-26 21:40:38 +01:00
|
|
|
if (tileRange.total > 10000) {
|
2022-01-07 17:31:39 +01:00
|
|
|
console.error("Got a really big tilerange, bounds and location might be out of sync")
|
|
|
|
return undefined
|
|
|
|
}
|
2022-01-26 21:40:38 +01:00
|
|
|
|
2021-09-26 17:36:39 +02:00
|
|
|
const needed = Tiles.MapRange(tileRange, (x, y) => Tiles.tile_index(zoomlevel, x, y)).filter(i => !self._loadedTiles.has(i))
|
2021-09-21 02:10:42 +02:00
|
|
|
if (needed.length === 0) {
|
2021-09-20 17:14:55 +02:00
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
return needed
|
|
|
|
}
|
2021-12-13 02:05:34 +01:00
|
|
|
, [layer.isDisplayed, state.currentBounds]).stabilized(250);
|
2021-09-21 02:10:42 +02:00
|
|
|
|
2021-09-20 17:14:55 +02:00
|
|
|
neededTiles.addCallbackAndRunD(neededIndexes => {
|
2021-11-07 16:34:51 +01:00
|
|
|
console.log("Tiled geojson source ", layer.layerDef.id, " needs", neededIndexes)
|
2021-09-21 02:10:42 +02:00
|
|
|
if (neededIndexes === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
2021-09-20 17:14:55 +02:00
|
|
|
for (const neededIndex of neededIndexes) {
|
|
|
|
self._loadedTiles.add(neededIndex)
|
2021-09-26 17:36:39 +02:00
|
|
|
const src = constructTile(Tiles.tile_from_index(neededIndex))
|
2021-11-07 16:34:51 +01:00
|
|
|
if (src !== undefined) {
|
2021-09-21 02:10:42 +02:00
|
|
|
self.loadedTiles.set(neededIndex, src)
|
2021-09-20 17:14:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-09-21 02:10:42 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|