Feature: add possibility to show a scale on the map

This commit is contained in:
Pieter Vander Vennet 2024-09-12 01:53:47 +02:00
parent 0fdbf445be
commit 5a9ae3f104
6 changed files with 52 additions and 10 deletions

View file

@ -1,6 +1,6 @@
{
"name": "mapcomplete",
"version": "0.46.5",
"version": "0.46.6",
"repository": "https://github.com/pietervdvn/MapComplete",
"description": "A small website to edit OSM easily",
"bugs": "https://github.com/pietervdvn/MapComplete/issues",

View file

@ -69,6 +69,8 @@ export default class UserRelatedState {
"button" | "button_click_right" | "button_click" | "click" | "click_right"
>("button_click_right")
public readonly showScale : UIEventSource<boolean>
/**
* Preferences as tags exposes many preferences and state properties as record.
* This is used to bridge the internal state with the usersettings.json layerconfig file
@ -123,6 +125,7 @@ export default class UserRelatedState {
documentation: "How adding a new feature is done",
}
)
this.showScale = UIEventSource.asBoolean(this.osmConnection.GetPreference("preference-show-scale","false"))
this.imageLicense = this.osmConnection.GetPreference("pictures-license", "CC0", {
documentation: "The license under which new images are uploaded",

View file

@ -22,6 +22,7 @@ export interface MapProperties {
readonly lastClickLocation: Store<{ lon: number; lat: number }>
readonly allowZooming: UIEventSource<true | boolean>
readonly useTerrain: Store<boolean>
readonly showScale: UIEventSource<boolean>
/**
* Triggered when the user navigated by using the keyboard.

View file

@ -889,6 +889,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
}
})
})
this.userRelatedState.showScale.addCallbackAndRun(showScale => {
this.mapProperties.showScale.set(showScale)
})
new ThemeViewStateHashActor(this)
new MetaTagging(this)
new TitleHandler(this.selectedElement, this.featureProperties, this)

View file

@ -1,5 +1,5 @@
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
import maplibregl, { Map as MLMap, Map as MlMap, SourceSpecification } from "maplibre-gl"
import maplibregl, { Map as MLMap, Map as MlMap, ScaleControl, SourceSpecification } from "maplibre-gl"
import { RasterLayerPolygon } from "../../Models/RasterLayers"
import { Utils } from "../../Utils"
import { BBox } from "../../Logic/BBox"
@ -23,13 +23,13 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
"dragRotate",
"dragPan",
"keyboard",
"touchZoomRotate",
"touchZoomRotate"
]
private static maplibre_zoom_handlers = [
"scrollZoom",
"boxZoom",
"doubleClickZoom",
"touchZoomRotate",
"touchZoomRotate"
]
readonly location: UIEventSource<{ lon: number; lat: number }>
readonly zoom: UIEventSource<number>
@ -47,6 +47,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
readonly rotation: UIEventSource<number>
readonly pitch: UIEventSource<number>
readonly useTerrain: Store<boolean>
readonly showScale: UIEventSource<boolean>
private static pmtilesInited = false
/**
@ -92,6 +93,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
this.useTerrain = state?.useTerrain ?? new ImmutableStore<boolean>(false)
this.rasterLayer =
state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined)
this.showScale = state?.showScale ?? new UIEventSource<boolean>(false)
const lastClickLocation = new UIEventSource<{
lat: number
@ -104,6 +106,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
const clickmodes = ["left", "middle", "right"] as const
function handleClick(e: maplibregl.MapMouseEvent, mode?: "left" | "right" | "middle") {
if (e.originalEvent["consumed"]) {
// Workaround, 'ShowPointLayer' sets this flag
@ -129,6 +132,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
self.setMaxzoom(self.maxzoom.data)
self.setBounds(self.bounds.data)
self.setTerrain(self.useTerrain.data)
self.setScale(self.showScale.data)
this.updateStores(true)
})
self.MoveMapToCurrentLoc(self.location.data)
@ -142,6 +146,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
self.setBounds(self.bounds.data)
self.SetRotation(self.rotation.data)
self.setTerrain(self.useTerrain.data)
self.setScale(self.showScale.data)
this.updateStores(true)
map.on("moveend", () => this.updateStores())
map.on("click", (e) => {
@ -213,6 +218,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
this.allowZooming.addCallbackAndRun((allowZooming) => self.setAllowZooming(allowZooming))
this.bounds.addCallbackAndRunD((bounds) => self.setBounds(bounds))
this.useTerrain?.addCallbackAndRun((useTerrain) => self.setTerrain(useTerrain))
this.showScale?.addCallbackAndRun(showScale => self.setScale(showScale))
}
/**
@ -227,9 +233,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
return {
map: mlmap,
ui: new SvelteUIElement(MaplibreMap, {
map: mlmap,
map: mlmap
}),
mapproperties: new MapLibreAdaptor(mlmap),
mapproperties: new MapLibreAdaptor(mlmap)
}
}
@ -297,7 +303,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
) {
const event = {
date: new Date(),
key: key,
key: key
}
for (let i = 0; i < this._onKeyNavigation.length; i++) {
@ -486,7 +492,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
const bounds = map.getBounds()
const bbox = new BBox([
[bounds.getEast(), bounds.getNorth()],
[bounds.getWest(), bounds.getSouth()],
[bounds.getWest(), bounds.getSouth()]
])
if (this.bounds.data === undefined || !isSetup) {
this.bounds.setData(bbox)
@ -664,18 +670,42 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
type: "raster-dem",
url:
"https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=" +
Constants.maptilerApiKey,
Constants.maptilerApiKey
})
try {
while (!map?.isStyleLoaded()) {
await Utils.waitFor(250)
}
map.setTerrain({
source: id,
source: id
})
} catch (e) {
console.error(e)
}
}
}
private scaleControl: maplibregl.ScaleControl = undefined
private setScale(showScale: boolean) {
const map = this._maplibreMap.data
if (!map) {
return
}
if (!showScale && this.scaleControl) {
map.removeControl(this.scaleControl)
return
}
console.log("Adding scale")
if (this.scaleControl === undefined) {
this.scaleControl = new ScaleControl({
maxWidth: 80,
unit: "metric"
})
}
if (!map.hasControl(this.scaleControl)) {
map.addControl(this.scaleControl, "bottom-right")
}
}
}

View file

@ -390,6 +390,11 @@
{/if}
</div>
</If>
<If condition={state.mapProperties.showScale}>
<div class="h-6">
<!-- Empty. We just provide some space for the maplibre scalecontrol -->
</div>
</If>
</div>
</div>
</div>