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
				
			
		|  | @ -36,6 +36,7 @@ export default class UserRelatedState { | |||
|     public readonly installedUserThemes: Store<string[]> | ||||
|     public readonly showAllQuestionsAtOnce: UIEventSource<boolean> | ||||
|     public readonly showTags: UIEventSource<"no" | undefined | "always" | "yes" | "full"> | ||||
|     public readonly fixateNorth: UIEventSource<undefined | "yes"> | ||||
|     public readonly homeLocation: FeatureSource | ||||
|     public readonly language: UIEventSource<string> | ||||
|     /** | ||||
|  | @ -87,7 +88,7 @@ export default class UserRelatedState { | |||
|         ) | ||||
|         this.language = this.osmConnection.GetPreference("language") | ||||
|         this.showTags = <UIEventSource<any>>this.osmConnection.GetPreference("show_tags") | ||||
| 
 | ||||
|         this.fixateNorth = <any>this.osmConnection.GetPreference("fixate-north") | ||||
|         this.mangroveIdentity = new MangroveIdentity( | ||||
|             this.osmConnection.GetLongPreference("identity", "mangrove") | ||||
|         ) | ||||
|  | @ -364,7 +365,14 @@ export default class UserRelatedState { | |||
|                     // Language is managed seperately
 | ||||
|                     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 maxbounds: UIEventSource<undefined | BBox> | ||||
|     readonly allowMoving: UIEventSource<true | boolean> | ||||
| 
 | ||||
|     readonly allowRotating: UIEventSource<true | boolean> | ||||
|     readonly lastClickLocation: Store<{ lon: number; lat: number }> | ||||
| 
 | ||||
|     readonly allowZooming: UIEventSource<true | boolean> | ||||
|  |  | |||
|  | @ -1,23 +1,27 @@ | |||
| import LayoutConfig from "./ThemeConfig/LayoutConfig" | ||||
| import {SpecialVisualizationState} from "../UI/SpecialVisualization" | ||||
| import {Changes} from "../Logic/Osm/Changes" | ||||
| import {ImmutableStore, Store, UIEventSource} from "../Logic/UIEventSource" | ||||
| import {FeatureSource, IndexedFeatureSource, WritableFeatureSource,} from "../Logic/FeatureSource/FeatureSource" | ||||
| import {OsmConnection} from "../Logic/Osm/OsmConnection" | ||||
| import {ExportableMap, MapProperties} from "./MapProperties" | ||||
| import { SpecialVisualizationState } from "../UI/SpecialVisualization" | ||||
| import { Changes } from "../Logic/Osm/Changes" | ||||
| import { ImmutableStore, Store, UIEventSource } from "../Logic/UIEventSource" | ||||
| import { | ||||
|     FeatureSource, | ||||
|     IndexedFeatureSource, | ||||
|     WritableFeatureSource, | ||||
| } from "../Logic/FeatureSource/FeatureSource" | ||||
| import { OsmConnection } from "../Logic/Osm/OsmConnection" | ||||
| import { ExportableMap, MapProperties } from "./MapProperties" | ||||
| import LayerState from "../Logic/State/LayerState" | ||||
| import {Feature, Point, Polygon} from "geojson" | ||||
| import { Feature, Point, Polygon } from "geojson" | ||||
| import FullNodeDatabaseSource from "../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource" | ||||
| import {Map as MlMap} from "maplibre-gl" | ||||
| import { Map as MlMap } from "maplibre-gl" | ||||
| import InitialMapPositioning from "../Logic/Actors/InitialMapPositioning" | ||||
| import {MapLibreAdaptor} from "../UI/Map/MapLibreAdaptor" | ||||
| import {GeoLocationState} from "../Logic/State/GeoLocationState" | ||||
| import { MapLibreAdaptor } from "../UI/Map/MapLibreAdaptor" | ||||
| import { GeoLocationState } from "../Logic/State/GeoLocationState" | ||||
| import FeatureSwitchState from "../Logic/State/FeatureSwitchState" | ||||
| import {QueryParameters} from "../Logic/Web/QueryParameters" | ||||
| import { QueryParameters } from "../Logic/Web/QueryParameters" | ||||
| import UserRelatedState from "../Logic/State/UserRelatedState" | ||||
| import LayerConfig from "./ThemeConfig/LayerConfig" | ||||
| import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler" | ||||
| import {AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils} from "./RasterLayers" | ||||
| import { AvailableRasterLayers, RasterLayerPolygon, RasterLayerUtils } from "./RasterLayers" | ||||
| import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource" | ||||
| import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource" | ||||
| import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore" | ||||
|  | @ -28,26 +32,28 @@ import TitleHandler from "../Logic/Actors/TitleHandler" | |||
| import ChangeToElementsActor from "../Logic/Actors/ChangeToElementsActor" | ||||
| import PendingChangesUploader from "../Logic/Actors/PendingChangesUploader" | ||||
| import SelectedElementTagsUpdater from "../Logic/Actors/SelectedElementTagsUpdater" | ||||
| import {BBox} from "../Logic/BBox" | ||||
| import { BBox } from "../Logic/BBox" | ||||
| import Constants from "./Constants" | ||||
| import Hotkeys from "../UI/Base/Hotkeys" | ||||
| import Translations from "../UI/i18n/Translations" | ||||
| import {GeoIndexedStoreForLayer} from "../Logic/FeatureSource/Actors/GeoIndexedStore" | ||||
| import {LastClickFeatureSource} from "../Logic/FeatureSource/Sources/LastClickFeatureSource" | ||||
| import {MenuState} from "./MenuState" | ||||
| import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore" | ||||
| import { LastClickFeatureSource } from "../Logic/FeatureSource/Sources/LastClickFeatureSource" | ||||
| import { MenuState } from "./MenuState" | ||||
| import MetaTagging from "../Logic/MetaTagging" | ||||
| import ChangeGeometryApplicator from "../Logic/FeatureSource/Sources/ChangeGeometryApplicator" | ||||
| import {NewGeometryFromChangesFeatureSource} from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource" | ||||
| import { NewGeometryFromChangesFeatureSource } from "../Logic/FeatureSource/Sources/NewGeometryFromChangesFeatureSource" | ||||
| import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader" | ||||
| import ShowOverlayRasterLayer from "../UI/Map/ShowOverlayRasterLayer" | ||||
| import {Utils} from "../Utils" | ||||
| import {EliCategory} from "./RasterLayerProperties" | ||||
| import { Utils } from "../Utils" | ||||
| import { EliCategory } from "./RasterLayerProperties" | ||||
| import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter" | ||||
| import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage" | ||||
| import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource" | ||||
| import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor" | ||||
| import NoElementsInViewDetector, {FeatureViewState,} from "../Logic/Actors/NoElementsInViewDetector" | ||||
| import FilteredLayer from "./FilteredLayer"; | ||||
| import NoElementsInViewDetector, { | ||||
|     FeatureViewState, | ||||
| } from "../Logic/Actors/NoElementsInViewDetector" | ||||
| import FilteredLayer from "./FilteredLayer" | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  | @ -69,6 +75,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
| 
 | ||||
|     readonly osmConnection: OsmConnection | ||||
|     readonly selectedElement: UIEventSource<Feature> | ||||
|     readonly selectedElementAndLayer: Store<{ feature: Feature; layer: LayerConfig }> | ||||
|     readonly mapProperties: MapProperties & ExportableMap | ||||
|     readonly osmObjectDownloader: OsmObjectDownloader | ||||
| 
 | ||||
|  | @ -133,8 +140,23 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|             layout, | ||||
|             this.featureSwitches | ||||
|         ) | ||||
|         this.userRelatedState.fixateNorth.addCallbackAndRunD((fixated) => { | ||||
|             this.mapProperties.allowRotating.setData(fixated !== "yes") | ||||
|         }) | ||||
|         this.selectedElement = new UIEventSource<Feature | undefined>(undefined, "Selected element") | ||||
|         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( | ||||
|             geolocationState, | ||||
|             this.selectedElement, | ||||
|  | @ -155,7 +177,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|                     rasterInfo.defaultState ?? true, | ||||
|                     "Wether or not overlayer layer " + rasterInfo.id + " is shown" | ||||
|                 ) | ||||
|                 const state = {isDisplayed} | ||||
|                 const state = { isDisplayed } | ||||
|                 overlayLayerStates.set(rasterInfo.id, state) | ||||
|                 new ShowOverlayRasterLayer(rasterInfo, this.map, this.mapProperties, state) | ||||
|             } | ||||
|  | @ -373,7 +395,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
| 
 | ||||
|     private initHotkeys() { | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             {nomod: "Escape", onUp: true}, | ||||
|             { nomod: "Escape", onUp: true }, | ||||
|             Translations.t.hotkeyDocumentation.closeSidebar, | ||||
|             () => { | ||||
|                 this.selectedElement.setData(undefined) | ||||
|  | @ -394,7 +416,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|         ) | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             {shift: "O"}, | ||||
|             { shift: "O" }, | ||||
|             Translations.t.hotkeyDocumentation.selectMapnik, | ||||
|             () => { | ||||
|                 this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto) | ||||
|  | @ -413,17 +435,17 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|         } | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             {nomod: "O"}, | ||||
|             { nomod: "O" }, | ||||
|             Translations.t.hotkeyDocumentation.selectOsmbasedmap, | ||||
|             () => setLayerCategory("osmbasedmap") | ||||
|         ) | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey({nomod: "M"}, Translations.t.hotkeyDocumentation.selectMap, () => | ||||
|         Hotkeys.RegisterHotkey({ nomod: "M" }, Translations.t.hotkeyDocumentation.selectMap, () => | ||||
|             setLayerCategory("map") | ||||
|         ) | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             {nomod: "P"}, | ||||
|             { nomod: "P" }, | ||||
|             Translations.t.hotkeyDocumentation.selectAerial, | ||||
|             () => setLayerCategory("photo") | ||||
|         ) | ||||
|  | @ -491,7 +513,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|             ), | ||||
|             range: new StaticFeatureSource( | ||||
|                 this.mapProperties.maxbounds.map((bbox) => | ||||
|                     bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({id: "range"})] | ||||
|                     bbox === undefined ? empty : <Feature[]>[bbox.asGeoJson({ id: "range" })] | ||||
|                 ) | ||||
|             ), | ||||
|             current_view: this.currentView, | ||||
|  | @ -521,12 +543,13 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|             }) | ||||
|         } | ||||
| 
 | ||||
|         const rangeFLayer: FilteredLayer = this.layerState.filteredLayers | ||||
|             .get("range") | ||||
|         const rangeFLayer: FilteredLayer = this.layerState.filteredLayers.get("range") | ||||
| 
 | ||||
|         const rangeIsDisplayed = rangeFLayer?.isDisplayed | ||||
| 
 | ||||
|         if (!QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef))) { | ||||
|         if ( | ||||
|             !QueryParameters.wasInitialized(FilteredLayer.queryParameterKey(rangeFLayer.layerDef)) | ||||
|         ) { | ||||
|             rangeIsDisplayed?.syncWith(this.featureSwitches.featureSwitchIsTesting, true) | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,6 +35,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|     readonly rasterLayer: UIEventSource<RasterLayerPolygon | undefined> | ||||
|     readonly maxbounds: UIEventSource<BBox | undefined> | ||||
|     readonly allowMoving: UIEventSource<true | boolean | undefined> | ||||
|     readonly allowRotating: UIEventSource<true | boolean | undefined> | ||||
|     readonly allowZooming: UIEventSource<true | boolean | undefined> | ||||
|     readonly lastClickLocation: Store<undefined | { lon: number; lat: number }> | ||||
|     readonly minzoom: UIEventSource<number> | ||||
|  | @ -69,6 +70,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|         }) | ||||
|         this.maxbounds = state?.maxbounds ?? new UIEventSource(undefined) | ||||
|         this.allowMoving = state?.allowMoving ?? new UIEventSource(true) | ||||
|         this.allowRotating = state?.allowRotating ?? new UIEventSource<boolean>(true) | ||||
|         this.allowZooming = state?.allowZooming ?? new UIEventSource(true) | ||||
|         this.bounds = state?.bounds ?? new UIEventSource(undefined) | ||||
|         this.rasterLayer = | ||||
|  | @ -95,6 +97,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|                 self.SetZoom(self.zoom.data) | ||||
|                 self.setMaxBounds(self.maxbounds.data) | ||||
|                 self.setAllowMoving(self.allowMoving.data) | ||||
|                 self.setAllowRotating(self.allowRotating.data) | ||||
|                 self.setAllowZooming(self.allowZooming.data) | ||||
|                 self.setMinzoom(self.minzoom.data) | ||||
|                 self.setMaxzoom(self.maxzoom.data) | ||||
|  | @ -105,6 +108,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|             self.SetZoom(self.zoom.data) | ||||
|             self.setMaxBounds(self.maxbounds.data) | ||||
|             self.setAllowMoving(self.allowMoving.data) | ||||
|             self.setAllowRotating(self.allowRotating.data) | ||||
|             self.setAllowZooming(self.allowZooming.data) | ||||
|             self.setMinzoom(self.minzoom.data) | ||||
|             self.setMaxzoom(self.maxzoom.data) | ||||
|  | @ -134,6 +138,9 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|         this.zoom.addCallbackAndRunD((z) => self.SetZoom(z)) | ||||
|         this.maxbounds.addCallbackAndRun((bbox) => self.setMaxBounds(bbox)) | ||||
|         this.allowMoving.addCallbackAndRun((allowMoving) => self.setAllowMoving(allowMoving)) | ||||
|         this.allowRotating.addCallbackAndRunD((allowRotating) => | ||||
|             self.setAllowRotating(allowRotating) | ||||
|         ) | ||||
|         this.allowZooming.addCallbackAndRun((allowZooming) => self.setAllowZooming(allowZooming)) | ||||
|         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.height = Math.ceil(drawOn.height * 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.height = map.getCanvas().height | ||||
| 
 | ||||
|         console.log("Canvas size:", drawOn.width, drawOn.height) | ||||
|         const ctx = drawOn.getContext("2d") | ||||
|         // Set up CSS size.
 | ||||
|         MapLibreAdaptor.setDpi(drawOn, ctx, dpiFactor / map.getPixelRatio()) | ||||
| 
 | ||||
|         await this.exportBackgroundOnCanvas(ctx) | ||||
| 
 | ||||
|         console.log("Getting markers") | ||||
|         // MapLibreAdaptor.setDpi(drawOn, ctx, 1)
 | ||||
|         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.scale(dpiFactor, dpiFactor) | ||||
|         this._maplibreMap.data?.resize() | ||||
|  | @ -288,14 +275,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|         } | ||||
|         const width = map.getCanvas().clientWidth | ||||
|         const height = map.getCanvas().clientHeight | ||||
|         console.log( | ||||
|             "Canvas size markers:", | ||||
|             map.getCanvas().width, | ||||
|             map.getCanvas().height, | ||||
|             "canvasClientRect:", | ||||
|             width, | ||||
|             height | ||||
|         ) | ||||
|         map.getCanvas().style.display = "none" | ||||
|         const img = await htmltoimage.toCanvas(map.getCanvasContainer(), { | ||||
|             pixelRatio: dpiFactor, | ||||
|  | @ -394,7 +373,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|             return | ||||
|         } | ||||
|         const background: RasterLayerProperties = this.rasterLayer?.data?.properties | ||||
|         console.log("Setting background to", background) | ||||
|         if (!background) { | ||||
|             console.error( | ||||
|                 "Attempting to 'setBackground', but the background is", | ||||
|  | @ -416,7 +394,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|         } | ||||
| 
 | ||||
|         if (background.type === "vector") { | ||||
|             console.log("Background layer is vector", background.id) | ||||
|             this.removeCurrentLayer(map) | ||||
|             map.setStyle(background.url) | ||||
|             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) { | ||||
|         const map = this._maplibreMap.data | ||||
|         if (!map) { | ||||
|  | @ -487,6 +479,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap { | |||
|                 map[id].enable() | ||||
|             } | ||||
|         } | ||||
|         this.setAllowRotating(this.allowRotating.data) | ||||
|     } | ||||
| 
 | ||||
|     private setMinzoom(minzoom: number) { | ||||
|  |  | |||
|  | @ -23,7 +23,6 @@ | |||
| 
 | ||||
|     export let attribution = false | ||||
|     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) | ||||
| 
 | ||||
|     const styleUrl = AvailableRasterLayers.maplibre.properties.url | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue