refactoring: more state splitting, basic layoutFeatureSource

This commit is contained in:
Pieter Vander Vennet 2023-03-26 05:58:28 +02:00
parent 8e2f04c0d0
commit b94a8f5745
54 changed files with 1067 additions and 1969 deletions

View file

@ -1,87 +1,65 @@
import FilteredLayer from "../../../Models/FilteredLayer"
import { FeatureSourceForLayer, Tiled } from "../FeatureSource"
import { UIEventSource } from "../../UIEventSource"
import TileHierarchy from "./TileHierarchy"
import { Store, Stores } from "../../UIEventSource"
import { Tiles } from "../../../Models/TileRange"
import { BBox } from "../../BBox"
import FeatureSource from "../FeatureSource"
import FeatureSourceMerger from "../Sources/FeatureSourceMerger"
/***
* 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>
private readonly _loadedTiles = new Set<number>()
export default class DynamicTileSource extends FeatureSourceMerger {
constructor(
layer: FilteredLayer,
zoomlevel: number,
constructTile: (zxy: [number, number, number]) => FeatureSourceForLayer & Tiled,
state: {
currentBounds: UIEventSource<BBox>
locationControl?: UIEventSource<{ zoom?: number }>
constructSource: (tileIndex) => FeatureSource,
mapProperties: {
bounds: Store<BBox>
zoom: Store<number>
},
options?: {
isActive?: Store<boolean>
}
) {
const self = this
this.loadedTiles = new Map<number, FeatureSourceForLayer & Tiled>()
const neededTiles = state.currentBounds
.map(
(bounds) => {
if (bounds === undefined) {
// We'll retry later
return undefined
}
if (!layer.isDisplayed.data && !layer.layerDef.forceLoad) {
// No need to download! - the layer is disabled
return undefined
}
if (
state.locationControl?.data?.zoom !== undefined &&
state.locationControl.data.zoom < layer.layerDef.minzoom
) {
// No need to download! - the layer is disabled
return undefined
}
const tileRange = Tiles.TileRangeBetween(
zoomlevel,
bounds.getNorth(),
bounds.getEast(),
bounds.getSouth(),
bounds.getWest()
)
if (tileRange.total > 10000) {
console.error(
"Got a really big tilerange, bounds and location might be out of sync"
super()
const loadedTiles = new Set<number>()
const neededTiles: Store<number[]> = Stores.ListStabilized(
mapProperties.bounds
.mapD(
(bounds) => {
if (options?.isActive?.data === false) {
// No need to download! - the layer is disabled
return undefined
}
const tileRange = Tiles.TileRangeBetween(
zoomlevel,
bounds.getNorth(),
bounds.getEast(),
bounds.getSouth(),
bounds.getWest()
)
return undefined
}
if (tileRange.total > 10000) {
console.error(
"Got a really big tilerange, bounds and location might be out of sync"
)
return undefined
}
const needed = Tiles.MapRange(tileRange, (x, y) =>
Tiles.tile_index(zoomlevel, x, y)
).filter((i) => !self._loadedTiles.has(i))
if (needed.length === 0) {
return undefined
}
return needed
},
[layer.isDisplayed, state.locationControl]
)
.stabilized(250)
const needed = Tiles.MapRange(tileRange, (x, y) =>
Tiles.tile_index(zoomlevel, x, y)
).filter((i) => !loadedTiles.has(i))
if (needed.length === 0) {
return undefined
}
return needed
},
[options?.isActive, mapProperties.zoom]
)
.stabilized(250)
)
neededTiles.addCallbackAndRunD((neededIndexes) => {
console.log("Tiled geojson source ", layer.layerDef.id, " needs", neededIndexes)
if (neededIndexes === undefined) {
return
}
for (const neededIndex of neededIndexes) {
self._loadedTiles.add(neededIndex)
const src = constructTile(Tiles.tile_from_index(neededIndex))
if (src !== undefined) {
self.loadedTiles.set(neededIndex, src)
}
loadedTiles.add(neededIndex)
super.addSource(constructSource(neededIndex))
}
})
}