forked from MapComplete/MapComplete
refactoring(maplibre): WIP
This commit is contained in:
parent
231d67361e
commit
4d48b1cf2b
89 changed files with 1166 additions and 3973 deletions
|
@ -1,34 +1,56 @@
|
|||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import type { Map as MLMap } from "maplibre-gl"
|
||||
import { Map as MlMap } from "maplibre-gl"
|
||||
import { RasterLayerPolygon, RasterLayerProperties } from "../../Models/RasterLayers"
|
||||
import { Utils } from "../../Utils"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import { MapProperties } from "../../Models/MapProperties"
|
||||
import SvelteUIElement from "../Base/SvelteUIElement"
|
||||
import MaplibreMap from "./MaplibreMap.svelte"
|
||||
import Constants from "../../Models/Constants"
|
||||
|
||||
export interface MapState {
|
||||
/**
|
||||
* The 'MapLibreAdaptor' bridges 'MapLibre' with the various properties of the `MapProperties`
|
||||
*/
|
||||
export class MapLibreAdaptor implements MapProperties {
|
||||
private static maplibre_control_handlers = [
|
||||
"scrollZoom",
|
||||
"boxZoom",
|
||||
"dragRotate",
|
||||
"dragPan",
|
||||
"keyboard",
|
||||
"doubleClickZoom",
|
||||
"touchZoomRotate",
|
||||
]
|
||||
readonly location: UIEventSource<{ lon: number; lat: number }>
|
||||
readonly zoom: UIEventSource<number>
|
||||
readonly bounds: Store<BBox>
|
||||
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
||||
}
|
||||
export class MapLibreAdaptor implements MapState {
|
||||
readonly maxbounds: UIEventSource<BBox | undefined>
|
||||
readonly allowMoving: UIEventSource<true | boolean | undefined>
|
||||
private readonly _maplibreMap: Store<MLMap>
|
||||
|
||||
readonly location: UIEventSource<{ lon: number; lat: number }>
|
||||
readonly zoom: UIEventSource<number>
|
||||
readonly bounds: Store<BBox>
|
||||
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
||||
private readonly _bounds: UIEventSource<BBox>
|
||||
|
||||
/**
|
||||
* Used for internal bookkeeping (to remove a rasterLayer when done loading)
|
||||
* @private
|
||||
*/
|
||||
private _currentRasterLayer: string
|
||||
constructor(maplibreMap: Store<MLMap>, state?: Partial<Omit<MapState, "bounds">>) {
|
||||
|
||||
constructor(maplibreMap: Store<MLMap>, state?: Partial<Omit<MapProperties, "bounds">>) {
|
||||
this._maplibreMap = maplibreMap
|
||||
|
||||
this.location = state?.location ?? new UIEventSource({ lon: 0, lat: 0 })
|
||||
this.zoom = state?.zoom ?? new UIEventSource(1)
|
||||
this.zoom.addCallbackAndRunD((z) => {
|
||||
if (z < 0) {
|
||||
this.zoom.setData(0)
|
||||
}
|
||||
if (z > 24) {
|
||||
this.zoom.setData(24)
|
||||
}
|
||||
})
|
||||
this.maxbounds = state?.maxbounds ?? new UIEventSource(undefined)
|
||||
this.allowMoving = state?.allowMoving ?? new UIEventSource(true)
|
||||
this._bounds = new UIEventSource(BBox.global)
|
||||
this.bounds = this._bounds
|
||||
this.rasterLayer =
|
||||
|
@ -38,20 +60,26 @@ export class MapLibreAdaptor implements MapState {
|
|||
maplibreMap.addCallbackAndRunD((map) => {
|
||||
map.on("load", () => {
|
||||
self.setBackground()
|
||||
self.MoveMapToCurrentLoc(self.location.data)
|
||||
self.SetZoom(self.zoom.data)
|
||||
self.setMaxBounds(self.maxbounds.data)
|
||||
self.setAllowMoving(self.allowMoving.data)
|
||||
})
|
||||
self.MoveMapToCurrentLoc(this.location.data)
|
||||
self.SetZoom(this.zoom.data)
|
||||
self.MoveMapToCurrentLoc(self.location.data)
|
||||
self.SetZoom(self.zoom.data)
|
||||
self.setMaxBounds(self.maxbounds.data)
|
||||
self.setAllowMoving(self.allowMoving.data)
|
||||
map.on("moveend", () => {
|
||||
const dt = this.location.data
|
||||
dt.lon = map.getCenter().lng
|
||||
dt.lat = map.getCenter().lat
|
||||
this.location.ping()
|
||||
this.zoom.setData(map.getZoom())
|
||||
this.zoom.setData(Math.round(map.getZoom() * 10) / 10)
|
||||
})
|
||||
})
|
||||
|
||||
this.rasterLayer.addCallback((_) =>
|
||||
self.setBackground().catch((e) => {
|
||||
self.setBackground().catch((_) => {
|
||||
console.error("Could not set background")
|
||||
})
|
||||
)
|
||||
|
@ -60,25 +88,25 @@ export class MapLibreAdaptor implements MapState {
|
|||
self.MoveMapToCurrentLoc(loc)
|
||||
})
|
||||
this.zoom.addCallbackAndRunD((z) => self.SetZoom(z))
|
||||
this.maxbounds.addCallbackAndRun((bbox) => self.setMaxBounds(bbox))
|
||||
this.allowMoving.addCallbackAndRun((allowMoving) => self.setAllowMoving(allowMoving))
|
||||
}
|
||||
private SetZoom(z: number) {
|
||||
const map = this._maplibreMap.data
|
||||
if (map === undefined || z === undefined) {
|
||||
return
|
||||
}
|
||||
if (map.getZoom() !== z) {
|
||||
map.setZoom(z)
|
||||
}
|
||||
}
|
||||
private MoveMapToCurrentLoc(loc: { lat: number; lon: number }) {
|
||||
const map = this._maplibreMap.data
|
||||
if (map === undefined || loc === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const center = map.getCenter()
|
||||
if (center.lng !== loc.lon || center.lat !== loc.lat) {
|
||||
map.setCenter({ lng: loc.lon, lat: loc.lat })
|
||||
/**
|
||||
* Convenience constructor
|
||||
*/
|
||||
public static construct(): {
|
||||
map: Store<MLMap>
|
||||
ui: SvelteUIElement
|
||||
mapproperties: MapProperties
|
||||
} {
|
||||
const mlmap = new UIEventSource<MlMap>(undefined)
|
||||
return {
|
||||
map: mlmap,
|
||||
ui: new SvelteUIElement(MaplibreMap, {
|
||||
map: mlmap,
|
||||
}),
|
||||
mapproperties: new MapLibreAdaptor(mlmap),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +131,6 @@ export class MapLibreAdaptor implements MapState {
|
|||
|
||||
const subdomains = url.match(/\{switch:([a-zA-Z0-9,]*)}/)
|
||||
if (subdomains !== null) {
|
||||
console.log("Found a switch:", subdomains)
|
||||
const options = subdomains[1].split(",")
|
||||
const option = options[Math.floor(Math.random() * options.length)]
|
||||
url = url.replace(subdomains[0], option)
|
||||
|
@ -112,6 +139,28 @@ export class MapLibreAdaptor implements MapState {
|
|||
return url
|
||||
}
|
||||
|
||||
private SetZoom(z: number) {
|
||||
const map = this._maplibreMap.data
|
||||
if (!map || z === undefined) {
|
||||
return
|
||||
}
|
||||
if (Math.abs(map.getZoom() - z) > 0.01) {
|
||||
map.setZoom(z)
|
||||
}
|
||||
}
|
||||
|
||||
private MoveMapToCurrentLoc(loc: { lat: number; lon: number }) {
|
||||
const map = this._maplibreMap.data
|
||||
if (!map || loc === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const center = map.getCenter()
|
||||
if (center.lng !== loc.lon || center.lat !== loc.lat) {
|
||||
map.setCenter({ lng: loc.lon, lat: loc.lat })
|
||||
}
|
||||
}
|
||||
|
||||
private async awaitStyleIsLoaded(): Promise<void> {
|
||||
const map = this._maplibreMap.data
|
||||
if (map === undefined) {
|
||||
|
@ -125,7 +174,6 @@ export class MapLibreAdaptor implements MapState {
|
|||
private removeCurrentLayer(map: MLMap) {
|
||||
if (this._currentRasterLayer) {
|
||||
// hide the previous layer
|
||||
console.log("Removing previous layer", this._currentRasterLayer)
|
||||
map.removeLayer(this._currentRasterLayer)
|
||||
map.removeSource(this._currentRasterLayer)
|
||||
}
|
||||
|
@ -185,4 +233,32 @@ export class MapLibreAdaptor implements MapState {
|
|||
this.removeCurrentLayer(map)
|
||||
this._currentRasterLayer = background?.id
|
||||
}
|
||||
|
||||
private setMaxBounds(bbox: undefined | BBox) {
|
||||
const map = this._maplibreMap.data
|
||||
if (map === undefined) {
|
||||
return
|
||||
}
|
||||
if (bbox) {
|
||||
map.setMaxBounds(bbox.toLngLat())
|
||||
} else {
|
||||
map.setMaxBounds(null)
|
||||
}
|
||||
}
|
||||
|
||||
private setAllowMoving(allow: true | boolean | undefined) {
|
||||
const map = this._maplibreMap.data
|
||||
if (map === undefined) {
|
||||
return
|
||||
}
|
||||
if (allow === false) {
|
||||
for (const id of MapLibreAdaptor.maplibre_control_handlers) {
|
||||
map[id].disable()
|
||||
}
|
||||
} else {
|
||||
for (const id of MapLibreAdaptor.maplibre_control_handlers) {
|
||||
map[id].enable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue