Performance: don't do an overpass request on every map pan if zoomed out too much

This commit is contained in:
Pieter Vander Vennet 2024-12-11 02:31:21 +01:00
parent 91a7957b85
commit 417bee2ee8
2 changed files with 21 additions and 28 deletions

View file

@ -1,4 +1,4 @@
import { Feature } from "geojson" import { Feature, Geometry } from "geojson"
import { UpdatableFeatureSource } from "../FeatureSource" import { UpdatableFeatureSource } from "../FeatureSource"
import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource" import { ImmutableStore, Store, UIEventSource } from "../../UIEventSource"
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
@ -7,6 +7,9 @@ import { Overpass } from "../../Osm/Overpass"
import { Utils } from "../../../Utils" import { Utils } from "../../../Utils"
import { TagsFilter } from "../../Tags/TagsFilter" import { TagsFilter } from "../../Tags/TagsFilter"
import { BBox } from "../../BBox" import { BBox } from "../../BBox"
import { FeatureCollection } from "@turf/turf"
import { OsmTags } from "../../../Models/OsmFeature"
"use strict";
/** /**
* A wrapper around the 'Overpass'-object. * A wrapper around the 'Overpass'-object.
@ -56,14 +59,13 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
this.state = state this.state = state
this._isActive = options?.isActive ?? new ImmutableStore(true) this._isActive = options?.isActive ?? new ImmutableStore(true)
this.padToZoomLevel = options?.padToTiles this.padToZoomLevel = options?.padToTiles
const self = this
this._layersToDownload = options?.ignoreZoom this._layersToDownload = options?.ignoreZoom
? new ImmutableStore(state.layers) ? new ImmutableStore(state.layers)
: state.zoom.map((zoom) => this.layersToDownload(zoom)) : state.zoom.map((zoom) => this.layersToDownload(zoom))
state.bounds.mapD( state.bounds.mapD(
(_) => { () => {
self.updateAsyncIfNeeded() this.updateAsyncIfNeeded()
}, },
[this._layersToDownload] [this._layersToDownload]
) )
@ -104,10 +106,11 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
/** /**
* Download the relevant data from overpass. Attempt to use a different server if one fails; only downloads the relevant layers * Download the relevant data from overpass. Attempt to use a different server if one fails; only downloads the relevant layers
* Will always attempt to download, even is 'options.isActive.data' is 'false', the zoom level is incorrect, ...
* @private * @private
*/ */
public async updateAsync(overrideBounds?: BBox): Promise<void> { public async updateAsync(overrideBounds?: BBox): Promise<void> {
let data: any = undefined let data: FeatureCollection<Geometry, OsmTags> = undefined
let lastUsed = 0 let lastUsed = 0
const start = new Date() const start = new Date()
const layersToDownload = this._layersToDownload.data const layersToDownload = this._layersToDownload.data
@ -116,8 +119,7 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
return return
} }
const self = this const overpassUrls = this.state.overpassUrl.data
const overpassUrls = self.state.overpassUrl.data
if (overpassUrls === undefined || overpassUrls.length === 0) { if (overpassUrls === undefined || overpassUrls.length === 0) {
throw "Panic: overpassFeatureSource didn't receive any overpassUrls" throw "Panic: overpassFeatureSource didn't receive any overpassUrls"
} }
@ -140,10 +142,11 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
return undefined return undefined
} }
this.runningQuery.setData(true) this.runningQuery.setData(true)
console.trace("Overpass feature source: querying geojson")
data = (await overpass.queryGeoJson(bounds))[0] data = (await overpass.queryGeoJson(bounds))[0]
} catch (e) { } catch (e) {
self.retries.data++ this.retries.data++
self.retries.ping() this.retries.ping()
console.error(`QUERY FAILED due to`, e) console.error(`QUERY FAILED due to`, e)
await Utils.waitFor(1000) await Utils.waitFor(1000)
@ -153,12 +156,12 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
console.log("Trying next time with", overpassUrls[lastUsed]) console.log("Trying next time with", overpassUrls[lastUsed])
} else { } else {
lastUsed = 0 lastUsed = 0
self.timeout.setData(self.retries.data * 5) this.timeout.setData(this.retries.data * 5)
while (self.timeout.data > 0) { while (this.timeout.data > 0) {
await Utils.waitFor(1000) await Utils.waitFor(1000)
self.timeout.data-- this.timeout.data--
self.timeout.ping() this.timeout.ping()
} }
} }
} }
@ -180,14 +183,14 @@ export default class OverpassFeatureSource implements UpdatableFeatureSource {
timeNeeded, timeNeeded,
"seconds" "seconds"
) )
self.features.setData(data.features) this.features.setData(data.features)
this._lastQueryBBox = bounds this._lastQueryBBox = bounds
this._lastRequestedLayers = layersToDownload this._lastRequestedLayers = layersToDownload
} catch (e) { } catch (e) {
console.error("Got the overpass response, but could not process it: ", e, e.stack) console.error("Got the overpass response, but could not process it: ", e, e.stack)
} finally { } finally {
self.retries.setData(0) this.retries.setData(0)
self.runningQuery.setData(false) this.runningQuery.setData(false)
} }
} }

View file

@ -24,8 +24,6 @@ export default class ThemeSource extends FeatureSourceMerger {
*/ */
public readonly isLoading: Store<boolean> public readonly isLoading: Store<boolean>
private readonly supportsForceDownload: UpdatableFeatureSource[]
public static readonly fromCacheZoomLevel = 15 public static readonly fromCacheZoomLevel = 15
/** /**
@ -44,8 +42,6 @@ export default class ThemeSource extends FeatureSourceMerger {
mvtAvailableLayers: Set<string>, mvtAvailableLayers: Set<string>,
fullNodeDatabaseSource?: FullNodeDatabaseSource fullNodeDatabaseSource?: FullNodeDatabaseSource
) { ) {
const supportsForceDownload: UpdatableFeatureSource[] = []
const { bounds, zoom } = mapProperties const { bounds, zoom } = mapProperties
// remove all 'special' layers // remove all 'special' layers
layers = layers.filter((layer) => layer.source !== null && layer.source !== undefined) layers = layers.filter((layer) => layer.source !== null && layer.source !== undefined)
@ -95,7 +91,6 @@ export default class ThemeSource extends FeatureSourceMerger {
) )
overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches) overpassSource = ThemeSource.setupOverpass(osmLayers, bounds, zoom, featureSwitches)
nonMvtSources.push(overpassSource) nonMvtSources.push(overpassSource)
supportsForceDownload.push(overpassSource)
} }
function setIsLoading() { function setIsLoading() {
@ -110,7 +105,6 @@ export default class ThemeSource extends FeatureSourceMerger {
ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) ThemeSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id))
) )
const downloadAllBounds: UIEventSource<BBox> = new UIEventSource<BBox>(undefined)
const downloadAll = new OverpassFeatureSource( const downloadAll = new OverpassFeatureSource(
{ {
layers: layers.filter((l) => l.isNormal()), layers: layers.filter((l) => l.isNormal()),
@ -123,6 +117,7 @@ export default class ThemeSource extends FeatureSourceMerger {
}, },
{ {
ignoreZoom: true, ignoreZoom: true,
isActive: new ImmutableStore(false)
} }
) )
@ -135,13 +130,8 @@ export default class ThemeSource extends FeatureSourceMerger {
) )
this.isLoading = isLoading this.isLoading = isLoading
supportsForceDownload.push(...geojsonSources)
supportsForceDownload.push(...mvtSources) // Non-mvt sources are handled by overpass
this._mapBounds = mapProperties.bounds
this._downloadAll = downloadAll this._downloadAll = downloadAll
this._mapBounds = mapProperties.bounds
this.supportsForceDownload = supportsForceDownload
} }
private static setupMvtSource( private static setupMvtSource(