Feature: add Protomaps as background layers

This commit is contained in:
Pieter Vander Vennet 2024-03-21 12:16:00 +01:00
parent 4ff67addf7
commit f2a6225c80
8 changed files with 272 additions and 104 deletions

View file

@ -1,6 +1,7 @@
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
import type { Map as MLMap } from "maplibre-gl"
import { Map as MLMap } from "maplibre-gl"
import { Map as MlMap, SourceSpecification } from "maplibre-gl"
import maplibregl from "maplibre-gl";
import { RasterLayerPolygon } from "../../Models/RasterLayers"
import { Utils } from "../../Utils"
import { BBox } from "../../Logic/BBox"
@ -11,7 +12,7 @@ import { RasterLayerProperties } from "../../Models/RasterLayerProperties"
import * as htmltoimage from "html-to-image"
import RasterLayerHandler from "./RasterLayerHandler"
import Constants from "../../Models/Constants"
import { Protocol } from "pmtiles";
/**
* The 'MapLibreAdaptor' bridges 'MapLibre' with the various properties of the `MapProperties`
*/
@ -46,6 +47,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
readonly pitch: UIEventSource<number>
readonly useTerrain: Store<boolean>
private static pmtilesInited = false
/**
* Functions that are called when one of those actions has happened
* @private
@ -55,6 +57,10 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
private readonly _maplibreMap: Store<MLMap>
constructor(maplibreMap: Store<MLMap>, state?: Partial<MapProperties>) {
if(!MapLibreAdaptor.pmtilesInited){
maplibregl.addProtocol("pmtiles",new Protocol().tile);
MapLibreAdaptor.pmtilesInited = true
}
this._maplibreMap = maplibreMap
this.location = state?.location ?? new UIEventSource(undefined)
@ -103,6 +109,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
}
maplibreMap.addCallbackAndRunD((map) => {
map.on("load", () => {
self.MoveMapToCurrentLoc(self.location.data)
self.SetZoom(self.zoom.data)
@ -212,7 +219,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
}
public static prepareWmsSource(layer: RasterLayerProperties): SourceSpecification {
return RasterLayerHandler.prepareWmsSource(layer)
return RasterLayerHandler.prepareSource(layer)
}
/**

View file

@ -1,8 +1,9 @@
import { Map as MLMap, SourceSpecification } from "maplibre-gl"
import { Map as MLMap, RasterSourceSpecification, VectorTileSource } from "maplibre-gl"
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
import { RasterLayerPolygon } from "../../Models/RasterLayers"
import { RasterLayerProperties } from "../../Models/RasterLayerProperties"
import { Utils } from "../../Utils"
import { VectorSourceSpecification } from "@maplibre/maplibre-gl-style-spec"
class SingleBackgroundHandler {
// Value between 0 and 1.0
@ -17,6 +18,7 @@ class SingleBackgroundHandler {
*/
public static readonly DEACTIVATE_AFTER = 60
private fadeStep = 0.1
constructor(
map: Store<MLMap>,
targetLayer: RasterLayerPolygon,
@ -75,6 +77,7 @@ class SingleBackgroundHandler {
this.fadeIn()
}
}
private async awaitStyleIsLoaded(): Promise<void> {
const map = this._map.data
if (!map) {
@ -85,11 +88,11 @@ class SingleBackgroundHandler {
}
}
private async enable(){
private async enable() {
let ttl = 15
await this.awaitStyleIsLoaded()
while(!this.tryEnable() && ttl > 0){
ttl --;
while (!this.tryEnable() && ttl > 0) {
ttl--
await Utils.waitFor(250)
}
}
@ -110,9 +113,10 @@ class SingleBackgroundHandler {
// The background layer is already an OSM-based map or another map, so we don't want anything from the baselayer
addLayerBeforeId = undefined
}
if (!map.getSource(background.id)) {
try {
map.addSource(background.id, RasterLayerHandler.prepareWmsSource(background))
map.addSource(background.id, RasterLayerHandler.prepareSource(background))
} catch (e) {
return false
}
@ -122,21 +126,25 @@ class SingleBackgroundHandler {
.getStyle()
.layers.find((l) => l.id.startsWith("mapcomplete_"))?.id
map.addLayer(
{
id: background.id,
type: "raster",
source: background.id,
paint: {
"raster-opacity": 0,
},
},
addLayerBeforeId
)
if (background.type === "vector") {
map.setStyle(background["style"])
} else {
this.opacity.addCallbackAndRun((o) => {
map.setPaintProperty(background.id, "raster-opacity", o)
})
map.addLayer(
{
id: background.id,
type: "raster",
source: background.id,
paint: {
"raster-opacity": 0
}
},
addLayerBeforeId
)
this.opacity.addCallbackAndRun((o) => {
map.setPaintProperty(background.id, "raster-opacity", o)
})
}
}
return true
}
@ -168,7 +176,14 @@ export default class RasterLayerHandler {
})
}
public static prepareWmsSource(layer: RasterLayerProperties): SourceSpecification {
public static prepareSource(layer: RasterLayerProperties): RasterSourceSpecification | VectorSourceSpecification {
if (layer.type === "vector") {
const vs: VectorSourceSpecification = {
type: "vector",
url: layer.url
}
return vs
}
return {
type: "raster",
// use the tiles option to specify a 256WMS tile source URL
@ -178,7 +193,7 @@ export default class RasterLayerHandler {
minzoom: layer["min_zoom"] ?? 1,
maxzoom: layer["max_zoom"] ?? 25,
// Bit of a hack, but seems to work
scheme: layer.url.includes("{-y}") ? "tms" : "xyz",
scheme: layer.url.includes("{-y}") ? "tms" : "xyz"
}
}
@ -192,7 +207,7 @@ export default class RasterLayerHandler {
"{width}": "" + size,
"{height}": "" + size,
"{zoom}": "{z}",
"{-y}": "{y}",
"{-y}": "{y}"
}
for (const key in toReplace) {