MapComplete/src/Logic/Actors/PreferredRasterLayerSelector.ts

96 lines
3.7 KiB
TypeScript

import { Store, UIEventSource } from "../UIEventSource"
import { AvailableRasterLayers, RasterLayerPolygon } from "../../Models/RasterLayers"
/**
* Selects the appropriate raster layer as background for the given query parameter, theme setting, user preference or default value.
*
* It the requested layer is not available, a layer of the same type will be selected.
*/
export class PreferredRasterLayerSelector {
private readonly _rasterLayerSetting: UIEventSource<RasterLayerPolygon>
private readonly _availableLayers: { store: Store<RasterLayerPolygon[]> }
private readonly _preferredBackgroundLayer: UIEventSource<
string | "photo" | "map" | "osmbasedmap" | undefined
>
private readonly _queryParameter: UIEventSource<string>
constructor(
rasterLayerSetting: UIEventSource<RasterLayerPolygon>,
availableLayers: { store: Store<RasterLayerPolygon[]> },
queryParameter: UIEventSource<string>,
preferredBackgroundLayer: UIEventSource<
string | "photo" | "map" | "osmbasedmap" | undefined
>
) {
this._rasterLayerSetting = rasterLayerSetting
this._availableLayers = availableLayers
this._queryParameter = queryParameter
this._preferredBackgroundLayer = preferredBackgroundLayer
const self = this
this._rasterLayerSetting.addCallbackD((layer) => {
if (layer.properties.id !== this._queryParameter.data) {
this._queryParameter.setData(undefined)
return true
}
})
this._queryParameter.addCallbackAndRunD((_) => {
const isApplied = self.updateLayer()
if (!isApplied) {
// A different layer was set as background
// We remove this queryParameter instead
self._queryParameter.setData(undefined)
return true // Unregister
}
})
this._preferredBackgroundLayer.addCallbackD((_) => self.updateLayer())
rasterLayerSetting.addCallbackAndRunD((layer) => {
if (AvailableRasterLayers.globalLayers.find((l) => l.id === layer.properties.id)) {
return
}
this._availableLayers.store.addCallbackD((_) => self.updateLayer())
return true // unregister
})
self.updateLayer()
}
/**
* Returns 'true' if the target layer is set or is the current layer
* @private
*/
private updateLayer() {
// What is the ID of the layer we have to (try to) load?
const targetLayerId = this._queryParameter.data ?? this._preferredBackgroundLayer.data
if (targetLayerId === undefined || targetLayerId === "default") {
return
}
const global = AvailableRasterLayers.globalLayers.find(
(l) => l.properties.id === targetLayerId
)
if (global) {
this._rasterLayerSetting.setData(global)
return
}
const isCategory =
targetLayerId === "photo" || targetLayerId === "osmbasedmap" || targetLayerId === "map"
const available = this._availableLayers.store.data
const foundLayer = isCategory
? available.find((l) => l.properties.category === targetLayerId)
: available.find((l) => l.properties.id === targetLayerId)
console.debug("Updating background layer to", foundLayer?.id, {
targetLayerId,
queryParam: this._queryParameter?.data,
preferred: this._preferredBackgroundLayer?.data,
isCategory,
})
if (foundLayer) {
this._rasterLayerSetting.setData(foundLayer)
return true
}
// The current layer is not in view
}
}