Feature: add possibility to show a scale on the map
This commit is contained in:
parent
0fdbf445be
commit
5a9ae3f104
6 changed files with 52 additions and 10 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.46.5",
|
"version": "0.46.6",
|
||||||
"repository": "https://github.com/pietervdvn/MapComplete",
|
"repository": "https://github.com/pietervdvn/MapComplete",
|
||||||
"description": "A small website to edit OSM easily",
|
"description": "A small website to edit OSM easily",
|
||||||
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
|
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
|
||||||
|
|
|
@ -69,6 +69,8 @@ export default class UserRelatedState {
|
||||||
"button" | "button_click_right" | "button_click" | "click" | "click_right"
|
"button" | "button_click_right" | "button_click" | "click" | "click_right"
|
||||||
>("button_click_right")
|
>("button_click_right")
|
||||||
|
|
||||||
|
public readonly showScale : UIEventSource<boolean>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferences as tags exposes many preferences and state properties as record.
|
* 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
|
* 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",
|
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", {
|
this.imageLicense = this.osmConnection.GetPreference("pictures-license", "CC0", {
|
||||||
documentation: "The license under which new images are uploaded",
|
documentation: "The license under which new images are uploaded",
|
||||||
|
|
|
@ -22,6 +22,7 @@ export interface MapProperties {
|
||||||
readonly lastClickLocation: Store<{ lon: number; lat: number }>
|
readonly lastClickLocation: Store<{ lon: number; lat: number }>
|
||||||
readonly allowZooming: UIEventSource<true | boolean>
|
readonly allowZooming: UIEventSource<true | boolean>
|
||||||
readonly useTerrain: Store<boolean>
|
readonly useTerrain: Store<boolean>
|
||||||
|
readonly showScale: UIEventSource<boolean>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggered when the user navigated by using the keyboard.
|
* Triggered when the user navigated by using the keyboard.
|
||||||
|
|
|
@ -889,6 +889,9 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
this.userRelatedState.showScale.addCallbackAndRun(showScale => {
|
||||||
|
this.mapProperties.showScale.set(showScale)
|
||||||
|
})
|
||||||
new ThemeViewStateHashActor(this)
|
new ThemeViewStateHashActor(this)
|
||||||
new MetaTagging(this)
|
new MetaTagging(this)
|
||||||
new TitleHandler(this.selectedElement, this.featureProperties, this)
|
new TitleHandler(this.selectedElement, this.featureProperties, this)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
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 { RasterLayerPolygon } from "../../Models/RasterLayers"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { BBox } from "../../Logic/BBox"
|
import { BBox } from "../../Logic/BBox"
|
||||||
|
@ -23,13 +23,13 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
"dragRotate",
|
"dragRotate",
|
||||||
"dragPan",
|
"dragPan",
|
||||||
"keyboard",
|
"keyboard",
|
||||||
"touchZoomRotate",
|
"touchZoomRotate"
|
||||||
]
|
]
|
||||||
private static maplibre_zoom_handlers = [
|
private static maplibre_zoom_handlers = [
|
||||||
"scrollZoom",
|
"scrollZoom",
|
||||||
"boxZoom",
|
"boxZoom",
|
||||||
"doubleClickZoom",
|
"doubleClickZoom",
|
||||||
"touchZoomRotate",
|
"touchZoomRotate"
|
||||||
]
|
]
|
||||||
readonly location: UIEventSource<{ lon: number; lat: number }>
|
readonly location: UIEventSource<{ lon: number; lat: number }>
|
||||||
readonly zoom: UIEventSource<number>
|
readonly zoom: UIEventSource<number>
|
||||||
|
@ -47,6 +47,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
readonly rotation: UIEventSource<number>
|
readonly rotation: UIEventSource<number>
|
||||||
readonly pitch: UIEventSource<number>
|
readonly pitch: UIEventSource<number>
|
||||||
readonly useTerrain: Store<boolean>
|
readonly useTerrain: Store<boolean>
|
||||||
|
readonly showScale: UIEventSource<boolean>
|
||||||
|
|
||||||
private static pmtilesInited = false
|
private static pmtilesInited = false
|
||||||
/**
|
/**
|
||||||
|
@ -92,6 +93,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
this.useTerrain = state?.useTerrain ?? new ImmutableStore<boolean>(false)
|
this.useTerrain = state?.useTerrain ?? new ImmutableStore<boolean>(false)
|
||||||
this.rasterLayer =
|
this.rasterLayer =
|
||||||
state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined)
|
state?.rasterLayer ?? new UIEventSource<RasterLayerPolygon | undefined>(undefined)
|
||||||
|
this.showScale = state?.showScale ?? new UIEventSource<boolean>(false)
|
||||||
|
|
||||||
const lastClickLocation = new UIEventSource<{
|
const lastClickLocation = new UIEventSource<{
|
||||||
lat: number
|
lat: number
|
||||||
|
@ -104,6 +106,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
|
new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
|
||||||
|
|
||||||
const clickmodes = ["left", "middle", "right"] as const
|
const clickmodes = ["left", "middle", "right"] as const
|
||||||
|
|
||||||
function handleClick(e: maplibregl.MapMouseEvent, mode?: "left" | "right" | "middle") {
|
function handleClick(e: maplibregl.MapMouseEvent, mode?: "left" | "right" | "middle") {
|
||||||
if (e.originalEvent["consumed"]) {
|
if (e.originalEvent["consumed"]) {
|
||||||
// Workaround, 'ShowPointLayer' sets this flag
|
// Workaround, 'ShowPointLayer' sets this flag
|
||||||
|
@ -129,6 +132,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
self.setMaxzoom(self.maxzoom.data)
|
self.setMaxzoom(self.maxzoom.data)
|
||||||
self.setBounds(self.bounds.data)
|
self.setBounds(self.bounds.data)
|
||||||
self.setTerrain(self.useTerrain.data)
|
self.setTerrain(self.useTerrain.data)
|
||||||
|
self.setScale(self.showScale.data)
|
||||||
this.updateStores(true)
|
this.updateStores(true)
|
||||||
})
|
})
|
||||||
self.MoveMapToCurrentLoc(self.location.data)
|
self.MoveMapToCurrentLoc(self.location.data)
|
||||||
|
@ -142,6 +146,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
self.setBounds(self.bounds.data)
|
self.setBounds(self.bounds.data)
|
||||||
self.SetRotation(self.rotation.data)
|
self.SetRotation(self.rotation.data)
|
||||||
self.setTerrain(self.useTerrain.data)
|
self.setTerrain(self.useTerrain.data)
|
||||||
|
self.setScale(self.showScale.data)
|
||||||
this.updateStores(true)
|
this.updateStores(true)
|
||||||
map.on("moveend", () => this.updateStores())
|
map.on("moveend", () => this.updateStores())
|
||||||
map.on("click", (e) => {
|
map.on("click", (e) => {
|
||||||
|
@ -213,6 +218,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
this.allowZooming.addCallbackAndRun((allowZooming) => self.setAllowZooming(allowZooming))
|
this.allowZooming.addCallbackAndRun((allowZooming) => self.setAllowZooming(allowZooming))
|
||||||
this.bounds.addCallbackAndRunD((bounds) => self.setBounds(bounds))
|
this.bounds.addCallbackAndRunD((bounds) => self.setBounds(bounds))
|
||||||
this.useTerrain?.addCallbackAndRun((useTerrain) => self.setTerrain(useTerrain))
|
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 {
|
return {
|
||||||
map: mlmap,
|
map: mlmap,
|
||||||
ui: new SvelteUIElement(MaplibreMap, {
|
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 = {
|
const event = {
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
key: key,
|
key: key
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._onKeyNavigation.length; i++) {
|
for (let i = 0; i < this._onKeyNavigation.length; i++) {
|
||||||
|
@ -486,7 +492,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
const bounds = map.getBounds()
|
const bounds = map.getBounds()
|
||||||
const bbox = new BBox([
|
const bbox = new BBox([
|
||||||
[bounds.getEast(), bounds.getNorth()],
|
[bounds.getEast(), bounds.getNorth()],
|
||||||
[bounds.getWest(), bounds.getSouth()],
|
[bounds.getWest(), bounds.getSouth()]
|
||||||
])
|
])
|
||||||
if (this.bounds.data === undefined || !isSetup) {
|
if (this.bounds.data === undefined || !isSetup) {
|
||||||
this.bounds.setData(bbox)
|
this.bounds.setData(bbox)
|
||||||
|
@ -664,18 +670,42 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
type: "raster-dem",
|
type: "raster-dem",
|
||||||
url:
|
url:
|
||||||
"https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=" +
|
"https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=" +
|
||||||
Constants.maptilerApiKey,
|
Constants.maptilerApiKey
|
||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
while (!map?.isStyleLoaded()) {
|
while (!map?.isStyleLoaded()) {
|
||||||
await Utils.waitFor(250)
|
await Utils.waitFor(250)
|
||||||
}
|
}
|
||||||
map.setTerrain({
|
map.setTerrain({
|
||||||
source: id,
|
source: id
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,11 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</If>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue