forked from MapComplete/MapComplete
Feature: allow to disable map rotation
This commit is contained in:
parent
bc385259ed
commit
2cc943889d
6 changed files with 108 additions and 65 deletions
|
@ -221,6 +221,26 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "fixate-north",
|
||||||
|
"question": {
|
||||||
|
"en": "Should north always be up?"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "mapcomplete-fixate-north=",
|
||||||
|
"then": {
|
||||||
|
"en": "Allow to rotate the map"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "mapcomplete-fixate-north=yes",
|
||||||
|
"then": {
|
||||||
|
"en": "Always keep north pointing up"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "mangrove-keys",
|
"id": "mangrove-keys",
|
||||||
"render": {
|
"render": {
|
||||||
|
|
|
@ -36,6 +36,7 @@ export default class UserRelatedState {
|
||||||
public readonly installedUserThemes: Store<string[]>
|
public readonly installedUserThemes: Store<string[]>
|
||||||
public readonly showAllQuestionsAtOnce: UIEventSource<boolean>
|
public readonly showAllQuestionsAtOnce: UIEventSource<boolean>
|
||||||
public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full">
|
public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full">
|
||||||
|
public readonly fixateNorth: UIEventSource<undefined | "yes">
|
||||||
public readonly homeLocation: FeatureSource
|
public readonly homeLocation: FeatureSource
|
||||||
public readonly language: UIEventSource<string>
|
public readonly language: UIEventSource<string>
|
||||||
/**
|
/**
|
||||||
|
@ -87,7 +88,7 @@ export default class UserRelatedState {
|
||||||
)
|
)
|
||||||
this.language = this.osmConnection.GetPreference("language")
|
this.language = this.osmConnection.GetPreference("language")
|
||||||
this.showTags = <UIEventSource<any>>this.osmConnection.GetPreference("show_tags")
|
this.showTags = <UIEventSource<any>>this.osmConnection.GetPreference("show_tags")
|
||||||
|
this.fixateNorth = <any>this.osmConnection.GetPreference("fixate-north")
|
||||||
this.mangroveIdentity = new MangroveIdentity(
|
this.mangroveIdentity = new MangroveIdentity(
|
||||||
this.osmConnection.GetLongPreference("identity", "mangrove")
|
this.osmConnection.GetLongPreference("identity", "mangrove")
|
||||||
)
|
)
|
||||||
|
@ -364,7 +365,14 @@ export default class UserRelatedState {
|
||||||
// Language is managed seperately
|
// Language is managed seperately
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
this.osmConnection.GetPreference(key, undefined, { prefix: "" }).setData(tags[key])
|
if (tags[key + "-combined-0"]) {
|
||||||
|
// A combined value exists
|
||||||
|
this.osmConnection.GetLongPreference(key, "").setData(tags[key])
|
||||||
|
} else {
|
||||||
|
this.osmConnection
|
||||||
|
.GetPreference(key, undefined, { prefix: "" })
|
||||||
|
.setData(tags[key])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export interface MapProperties {
|
||||||
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
||||||
readonly maxbounds: UIEventSource<undefined | BBox>
|
readonly maxbounds: UIEventSource<undefined | BBox>
|
||||||
readonly allowMoving: UIEventSource<true | boolean>
|
readonly allowMoving: UIEventSource<true | boolean>
|
||||||
|
readonly allowRotating: UIEventSource<true | boolean>
|
||||||
readonly lastClickLocation: Store<{ lon: number; lat: number }>
|
readonly lastClickLocation: Store<{ lon: number; lat: number }>
|
||||||
|
|
||||||
readonly allowZooming: UIEventSource<true | boolean>
|
readonly allowZooming: UIEventSource<true | boolean>
|
||||||
|
|
|
@ -2,7 +2,11 @@ import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
||||||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||||
import { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../Logic/UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import {FeatureSource, IndexedFeatureSource, WritableFeatureSource,} from "../Logic/FeatureSource/FeatureSource"
|
import {
|
||||||
|
FeatureSource,
|
||||||
|
IndexedFeatureSource,
|
||||||
|
WritableFeatureSource,
|
||||||
|
} from "../Logic/FeatureSource/FeatureSource"
|
||||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { ExportableMap, MapProperties } from "./MapProperties"
|
import { ExportableMap, MapProperties } from "./MapProperties"
|
||||||
import LayerState from "../Logic/State/LayerState"
|
import LayerState from "../Logic/State/LayerState"
|
||||||
|
@ -46,8 +50,10 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"
|
||||||
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
||||||
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
||||||
import NoElementsInViewDetector, {FeatureViewState,} from "../Logic/Actors/NoElementsInViewDetector"
|
import NoElementsInViewDetector, {
|
||||||
import FilteredLayer from "./FilteredLayer";
|
FeatureViewState,
|
||||||
|
} from "../Logic/Actors/NoElementsInViewDetector"
|
||||||
|
import FilteredLayer from "./FilteredLayer"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -69,6 +75,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
|
|
||||||
readonly osmConnection: OsmConnection
|
readonly osmConnection: OsmConnection
|
||||||
readonly selectedElement: UIEventSource<Feature>
|
readonly selectedElement: UIEventSource<Feature>
|
||||||
|
readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }>
|
||||||
readonly mapProperties: MapProperties & ExportableMap
|
readonly mapProperties: MapProperties & ExportableMap
|
||||||
readonly osmObjectDownloader: OsmObjectDownloader
|
readonly osmObjectDownloader: OsmObjectDownloader
|
||||||
|
|
||||||
|
@ -133,8 +140,23 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
layout,
|
layout,
|
||||||
this.featureSwitches
|
this.featureSwitches
|
||||||
)
|
)
|
||||||
|
this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => {
|
||||||
|
this.mapProperties.allowRotating.setData(fixated !== "yes")
|
||||||
|
})
|
||||||
this.selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element")
|
this.selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element")
|
||||||
this.selectedLayer = new UIEventSource<LayerConfig>(undefined, "Selected layer")
|
this.selectedLayer = new UIEventSource<LayerConfig>(undefined, "Selected layer")
|
||||||
|
|
||||||
|
this.selectedElementAndLayer = this.selectedElement.mapD(
|
||||||
|
(feature) => {
|
||||||
|
const layer = this.selectedLayer.data
|
||||||
|
if (!layer) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return { layer, feature }
|
||||||
|
},
|
||||||
|
[this.selectedLayer]
|
||||||
|
)
|
||||||
|
|
||||||
this.geolocation = new GeoLocationHandler(
|
this.geolocation = new GeoLocationHandler(
|
||||||
geolocationState,
|
geolocationState,
|
||||||
this.selectedElement,
|
this.selectedElement,
|
||||||
|
@ -521,12 +543,13 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const rangeFLayer: FilteredLayer = this.layerState.filteredLayers
|
const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range")
|
||||||
.get("range")
|
|
||||||
|
|
||||||
const rangeIsDisplayed = rangeFLayer?.isDisplayed
|
const rangeIsDisplayed = rangeFLayer?.isDisplayed
|
||||||
|
|
||||||
if (!QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef))) {
|
if (
|
||||||
|
!QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef))
|
||||||
|
) {
|
||||||
rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true)
|
rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined>
|
||||||
readonly maxbounds: UIEventSource<BBox | undefined>
|
readonly maxbounds: UIEventSource<BBox | undefined>
|
||||||
readonly allowMoving: UIEventSource<true | boolean | undefined>
|
readonly allowMoving: UIEventSource<true | boolean | undefined>
|
||||||
|
readonly allowRotating: UIEventSource<true | boolean | undefined>
|
||||||
readonly allowZooming: UIEventSource<true | boolean | undefined>
|
readonly allowZooming: UIEventSource<true | boolean | undefined>
|
||||||
readonly lastClickLocation: Store<undefined | { lon: number; lat: number }>
|
readonly lastClickLocation: Store<undefined | { lon: number; lat: number }>
|
||||||
readonly minzoom: UIEventSource<number>
|
readonly minzoom: UIEventSource<number>
|
||||||
|
@ -69,6 +70,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
})
|
})
|
||||||
this.maxbounds = state?.maxbounds ?? new UIEventSource(undefined)
|
this.maxbounds = state?.maxbounds ?? new UIEventSource(undefined)
|
||||||
this.allowMoving = state?.allowMoving ?? new UIEventSource(true)
|
this.allowMoving = state?.allowMoving ?? new UIEventSource(true)
|
||||||
|
this.allowRotating = state?.allowRotating ?? new UIEventSource<boolean>(true)
|
||||||
this.allowZooming = state?.allowZooming ?? new UIEventSource(true)
|
this.allowZooming = state?.allowZooming ?? new UIEventSource(true)
|
||||||
this.bounds = state?.bounds ?? new UIEventSource(undefined)
|
this.bounds = state?.bounds ?? new UIEventSource(undefined)
|
||||||
this.rasterLayer =
|
this.rasterLayer =
|
||||||
|
@ -95,6 +97,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
self.SetZoom(self.zoom.data)
|
self.SetZoom(self.zoom.data)
|
||||||
self.setMaxBounds(self.maxbounds.data)
|
self.setMaxBounds(self.maxbounds.data)
|
||||||
self.setAllowMoving(self.allowMoving.data)
|
self.setAllowMoving(self.allowMoving.data)
|
||||||
|
self.setAllowRotating(self.allowRotating.data)
|
||||||
self.setAllowZooming(self.allowZooming.data)
|
self.setAllowZooming(self.allowZooming.data)
|
||||||
self.setMinzoom(self.minzoom.data)
|
self.setMinzoom(self.minzoom.data)
|
||||||
self.setMaxzoom(self.maxzoom.data)
|
self.setMaxzoom(self.maxzoom.data)
|
||||||
|
@ -105,6 +108,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
self.SetZoom(self.zoom.data)
|
self.SetZoom(self.zoom.data)
|
||||||
self.setMaxBounds(self.maxbounds.data)
|
self.setMaxBounds(self.maxbounds.data)
|
||||||
self.setAllowMoving(self.allowMoving.data)
|
self.setAllowMoving(self.allowMoving.data)
|
||||||
|
self.setAllowRotating(self.allowRotating.data)
|
||||||
self.setAllowZooming(self.allowZooming.data)
|
self.setAllowZooming(self.allowZooming.data)
|
||||||
self.setMinzoom(self.minzoom.data)
|
self.setMinzoom(self.minzoom.data)
|
||||||
self.setMaxzoom(self.maxzoom.data)
|
self.setMaxzoom(self.maxzoom.data)
|
||||||
|
@ -134,6 +138,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
this.zoom.addCallbackAndRunD((z) => self.SetZoom(z))
|
this.zoom.addCallbackAndRunD((z) => self.SetZoom(z))
|
||||||
this.maxbounds.addCallbackAndRun((bbox) => self.setMaxBounds(bbox))
|
this.maxbounds.addCallbackAndRun((bbox) => self.setMaxBounds(bbox))
|
||||||
this.allowMoving.addCallbackAndRun((allowMoving) => self.setAllowMoving(allowMoving))
|
this.allowMoving.addCallbackAndRun((allowMoving) => self.setAllowMoving(allowMoving))
|
||||||
|
this.allowRotating.addCallbackAndRunD((allowRotating) =>
|
||||||
|
self.setAllowRotating(allowRotating)
|
||||||
|
)
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
@ -181,13 +188,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
drawOn.width = Math.ceil(drawOn.width * dpiFactor)
|
drawOn.width = Math.ceil(drawOn.width * dpiFactor)
|
||||||
drawOn.height = Math.ceil(drawOn.height * dpiFactor)
|
drawOn.height = Math.ceil(drawOn.height * dpiFactor)
|
||||||
ctx.scale(dpiFactor, dpiFactor)
|
ctx.scale(dpiFactor, dpiFactor)
|
||||||
console.log(
|
|
||||||
"Resizing canvas with setDPI:",
|
|
||||||
drawOn.width,
|
|
||||||
drawOn.height,
|
|
||||||
drawOn.style.width,
|
|
||||||
drawOn.style.height
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,27 +228,14 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
drawOn.width = map.getCanvas().width
|
drawOn.width = map.getCanvas().width
|
||||||
drawOn.height = map.getCanvas().height
|
drawOn.height = map.getCanvas().height
|
||||||
|
|
||||||
console.log("Canvas size:", drawOn.width, drawOn.height)
|
|
||||||
const ctx = drawOn.getContext("2d")
|
const ctx = drawOn.getContext("2d")
|
||||||
// Set up CSS size.
|
// Set up CSS size.
|
||||||
MapLibreAdaptor.setDpi(drawOn, ctx, dpiFactor / map.getPixelRatio())
|
MapLibreAdaptor.setDpi(drawOn, ctx, dpiFactor / map.getPixelRatio())
|
||||||
|
|
||||||
await this.exportBackgroundOnCanvas(ctx)
|
await this.exportBackgroundOnCanvas(ctx)
|
||||||
|
|
||||||
console.log("Getting markers")
|
|
||||||
// MapLibreAdaptor.setDpi(drawOn, ctx, 1)
|
// MapLibreAdaptor.setDpi(drawOn, ctx, 1)
|
||||||
const markers = await this.drawMarkers(dpiFactor)
|
const markers = await this.drawMarkers(dpiFactor)
|
||||||
console.log(
|
|
||||||
"Drawing markers (" +
|
|
||||||
markers.width +
|
|
||||||
"*" +
|
|
||||||
markers.height +
|
|
||||||
") onto drawOn (" +
|
|
||||||
drawOn.width +
|
|
||||||
"*" +
|
|
||||||
drawOn.height +
|
|
||||||
")"
|
|
||||||
)
|
|
||||||
ctx.drawImage(markers, 0, 0, drawOn.width, drawOn.height)
|
ctx.drawImage(markers, 0, 0, drawOn.width, drawOn.height)
|
||||||
ctx.scale(dpiFactor, dpiFactor)
|
ctx.scale(dpiFactor, dpiFactor)
|
||||||
this._maplibreMap.data?.resize()
|
this._maplibreMap.data?.resize()
|
||||||
|
@ -288,14 +275,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
}
|
}
|
||||||
const width = map.getCanvas().clientWidth
|
const width = map.getCanvas().clientWidth
|
||||||
const height = map.getCanvas().clientHeight
|
const height = map.getCanvas().clientHeight
|
||||||
console.log(
|
|
||||||
"Canvas size markers:",
|
|
||||||
map.getCanvas().width,
|
|
||||||
map.getCanvas().height,
|
|
||||||
"canvasClientRect:",
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
)
|
|
||||||
map.getCanvas().style.display = "none"
|
map.getCanvas().style.display = "none"
|
||||||
const img = await htmltoimage.toCanvas(map.getCanvasContainer(), {
|
const img = await htmltoimage.toCanvas(map.getCanvasContainer(), {
|
||||||
pixelRatio: dpiFactor,
|
pixelRatio: dpiFactor,
|
||||||
|
@ -394,7 +373,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const background: RasterLayerProperties = this.rasterLayer?.data?.properties
|
const background: RasterLayerProperties = this.rasterLayer?.data?.properties
|
||||||
console.log("Setting background to", background)
|
|
||||||
if (!background) {
|
if (!background) {
|
||||||
console.error(
|
console.error(
|
||||||
"Attempting to 'setBackground', but the background is",
|
"Attempting to 'setBackground', but the background is",
|
||||||
|
@ -416,7 +394,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (background.type === "vector") {
|
if (background.type === "vector") {
|
||||||
console.log("Background layer is vector", background.id)
|
|
||||||
this.removeCurrentLayer(map)
|
this.removeCurrentLayer(map)
|
||||||
map.setStyle(background.url)
|
map.setStyle(background.url)
|
||||||
return
|
return
|
||||||
|
@ -473,6 +450,21 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private setAllowRotating(allow: true | boolean | undefined) {
|
||||||
|
const map = this._maplibreMap.data
|
||||||
|
if (!map) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log("Rotation allowed:", allow)
|
||||||
|
if (allow === false) {
|
||||||
|
map.rotateTo(0, { duration: 0 })
|
||||||
|
map.setPitch(0)
|
||||||
|
map.dragRotate.disable()
|
||||||
|
} else {
|
||||||
|
map.dragRotate.enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private setAllowMoving(allow: true | boolean | undefined) {
|
private setAllowMoving(allow: true | boolean | undefined) {
|
||||||
const map = this._maplibreMap.data
|
const map = this._maplibreMap.data
|
||||||
if (!map) {
|
if (!map) {
|
||||||
|
@ -487,6 +479,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
|
||||||
map[id].enable()
|
map[id].enable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.setAllowRotating(this.allowRotating.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private setMinzoom(minzoom: number) {
|
private setMinzoom(minzoom: number) {
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
export let attribution = false
|
export let attribution = false
|
||||||
export let center: {lng: number, lat: number} | Readable<{ lng: number; lat: number }> = writable({lng: 0, lat: 0})
|
export let center: {lng: number, lat: number} | Readable<{ lng: number; lat: number }> = writable({lng: 0, lat: 0})
|
||||||
console.trace("Center is", center)
|
|
||||||
export let zoom: Readable<number> = writable(1)
|
export let zoom: Readable<number> = writable(1)
|
||||||
|
|
||||||
const styleUrl = AvailableRasterLayers.maplibre.properties.url
|
const styleUrl = AvailableRasterLayers.maplibre.properties.url
|
||||||
|
|
Loading…
Reference in a new issue