forked from MapComplete/MapComplete
		
	refactoring(maplibre): WIP
This commit is contained in:
		
							parent
							
								
									231d67361e
								
							
						
					
					
						commit
						4d48b1cf2b
					
				
					 89 changed files with 1166 additions and 3973 deletions
				
			
		|  | @ -1,51 +1,31 @@ | |||
| import UserRelatedState from "./UserRelatedState" | ||||
| import { Store, Stores, UIEventSource } from "../UIEventSource" | ||||
| import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | ||||
| import { Store, UIEventSource } from "../UIEventSource" | ||||
| import Attribution from "../../UI/BigComponents/Attribution" | ||||
| import Minimap, { MinimapObj } from "../../UI/Base/Minimap" | ||||
| import { Tiles } from "../../Models/TileRange" | ||||
| import BaseUIElement from "../../UI/BaseUIElement" | ||||
| import FilteredLayer, { FilterState } from "../../Models/FilteredLayer" | ||||
| import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig" | ||||
| import { QueryParameters } from "../Web/QueryParameters" | ||||
| import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer" | ||||
| import { FeatureSourceForLayer, Tiled } from "../FeatureSource/FeatureSource" | ||||
| import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource" | ||||
| import { LocalStorageSource } from "../Web/LocalStorageSource" | ||||
| import { GeoOperations } from "../GeoOperations" | ||||
| import TitleHandler from "../Actors/TitleHandler" | ||||
| import { BBox } from "../BBox" | ||||
| import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | ||||
| import { TiledStaticFeatureSource } from "../FeatureSource/Sources/StaticFeatureSource" | ||||
| import { Translation, TypedTranslation } from "../../UI/i18n/Translation" | ||||
| import { Tag } from "../Tags/Tag" | ||||
| import StaticFeatureSource, { | ||||
|     TiledStaticFeatureSource, | ||||
| } from "../FeatureSource/Sources/StaticFeatureSource" | ||||
| import { OsmConnection } from "../Osm/OsmConnection" | ||||
| import { Feature, LineString } from "geojson" | ||||
| import { OsmTags } from "../../Models/OsmFeature" | ||||
| 
 | ||||
| export interface GlobalFilter { | ||||
|     filter: FilterState | ||||
|     id: string | ||||
|     onNewPoint: { | ||||
|         safetyCheck: Translation | ||||
|         confirmAddNew: TypedTranslation<{ preset: Translation }> | ||||
|         tags: Tag[] | ||||
|     } | ||||
| } | ||||
| import { Feature } from "geojson" | ||||
| import { Map as MlMap } from "maplibre-gl" | ||||
| import { GlobalFilter } from "../../Models/GlobalFilter" | ||||
| import { MapProperties } from "../../Models/MapProperties" | ||||
| import ShowDataLayer from "../../UI/Map/ShowDataLayer" | ||||
| 
 | ||||
| /** | ||||
|  * Contains all the leaflet-map related state | ||||
|  */ | ||||
| export default class MapState extends UserRelatedState { | ||||
|     /** | ||||
|      The leaflet instance of the big basemap | ||||
|      */ | ||||
|     public leafletMap = new UIEventSource<any /*L.Map*/>(undefined, "leafletmap") | ||||
| export default class MapState { | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * The current background layer | ||||
|      */ | ||||
|     public backgroundLayer: UIEventSource<BaseLayer> | ||||
|     /** | ||||
|      * Last location where a click was registered | ||||
|      */ | ||||
|  | @ -58,34 +38,6 @@ export default class MapState extends UserRelatedState { | |||
|      * The bounds of the current map view | ||||
|      */ | ||||
|     public currentView: FeatureSourceForLayer & Tiled | ||||
|     /** | ||||
|      * The location as delivered by the GPS | ||||
|      */ | ||||
|     public currentUserLocation: SimpleFeatureSource | ||||
| 
 | ||||
|     /** | ||||
|      * All previously visited points, with their metadata | ||||
|      */ | ||||
|     public historicalUserLocations: SimpleFeatureSource | ||||
|     /** | ||||
|      * The number of seconds that the GPS-locations are stored in memory. | ||||
|      * Time in seconds | ||||
|      */ | ||||
|     public gpsLocationHistoryRetentionTime = new UIEventSource( | ||||
|         7 * 24 * 60 * 60, | ||||
|         "gps_location_retention" | ||||
|     ) | ||||
|     /** | ||||
|      * A featureSource containing a single linestring which has the GPS-history of the user. | ||||
|      * However, metadata (such as when every single point was visited) is lost here (but is kept in `historicalUserLocations`. | ||||
|      * Note that this featureSource is _derived_ from 'historicalUserLocations' | ||||
|      */ | ||||
|     public historicalUserLocationsTrack: FeatureSourceForLayer & Tiled | ||||
| 
 | ||||
|     /** | ||||
|      * A feature source containing the current home location of the user | ||||
|      */ | ||||
|     public homeLocation: FeatureSourceForLayer & Tiled | ||||
| 
 | ||||
|     /** | ||||
|      * A builtin layer which contains the selected element. | ||||
|  | @ -94,7 +46,7 @@ export default class MapState extends UserRelatedState { | |||
|      */ | ||||
|     public selectedElementsLayer: FeatureSourceForLayer & Tiled | ||||
| 
 | ||||
|     public readonly mainMapObject: BaseUIElement & MinimapObj | ||||
|     public readonly mainMapObject: BaseUIElement | ||||
| 
 | ||||
|     /** | ||||
|      * Which layers are enabled in the current theme and what filters are applied onto them | ||||
|  | @ -114,9 +66,7 @@ export default class MapState extends UserRelatedState { | |||
|      */ | ||||
|     public overlayToggles: { config: TilesourceConfig; isDisplayed: UIEventSource<boolean> }[] | ||||
| 
 | ||||
|     constructor(layoutToUse: LayoutConfig, options?: { attemptLogin: true | boolean }) { | ||||
|         super(layoutToUse, options) | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(this.locationControl) | ||||
| 
 | ||||
|         let defaultLayer = AvailableBaseLayers.osmCarto | ||||
|  | @ -130,13 +80,6 @@ export default class MapState extends UserRelatedState { | |||
|         this.backgroundLayer = new UIEventSource<BaseLayer>(defaultLayer) | ||||
|         this.backgroundLayer.addCallbackAndRunD((layer) => self.backgroundLayerId.setData(layer.id)) | ||||
| 
 | ||||
|         const attr = new Attribution( | ||||
|             this.locationControl, | ||||
|             this.osmConnection.userDetails, | ||||
|             this.layoutToUse, | ||||
|             this.currentBounds | ||||
|         ) | ||||
| 
 | ||||
|         // Will write into this.leafletMap
 | ||||
|         this.mainMapObject = Minimap.createMiniMap({ | ||||
|             background: this.backgroundLayer, | ||||
|  | @ -162,12 +105,8 @@ export default class MapState extends UserRelatedState { | |||
|             MapState.InitializeFilteredLayers(this.layoutToUse, this.osmConnection) | ||||
|         ) | ||||
| 
 | ||||
|         this.lockBounds() | ||||
|         this.AddAllOverlaysToMap(this.leafletMap) | ||||
| 
 | ||||
|         this.initHomeLocation() | ||||
|         this.initGpsLocation() | ||||
|         this.initUserLocationTrail() | ||||
|         this.initCurrentView() | ||||
|         this.initSelectedElement() | ||||
| 
 | ||||
|  | @ -189,17 +128,6 @@ export default class MapState extends UserRelatedState { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private lockBounds() { | ||||
|         const layout = this.layoutToUse | ||||
|         if (!layout?.lockLocation) { | ||||
|             return | ||||
|         } | ||||
|         console.warn("Locking the bounds to ", layout.lockLocation) | ||||
|         this.mainMapObject.installBounds( | ||||
|             new BBox(layout.lockLocation), | ||||
|             this.featureSwitchIsTesting.data | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     private initCurrentView() { | ||||
|         let currentViewLayer: FilteredLayer = this.filteredLayers.data.filter( | ||||
|  | @ -244,17 +172,6 @@ export default class MapState extends UserRelatedState { | |||
|         this.currentView = new TiledStaticFeatureSource(features, currentViewLayer) | ||||
|     } | ||||
| 
 | ||||
|     private initGpsLocation() { | ||||
|         // Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
 | ||||
|         const gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter( | ||||
|             (l) => l.layerDef.id === "gps_location" | ||||
|         )[0] | ||||
|         if (gpsLayerDef === undefined) { | ||||
|             return | ||||
|         } | ||||
|         this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0)) | ||||
|     } | ||||
| 
 | ||||
|     private initSelectedElement() { | ||||
|         const layerDef: FilteredLayer = this.filteredLayers.data.filter( | ||||
|             (l) => l.layerDef.id === "selected_element" | ||||
|  | @ -281,145 +198,6 @@ export default class MapState extends UserRelatedState { | |||
|         this.selectedElementsLayer = new TiledStaticFeatureSource(store, layerDef) | ||||
|     } | ||||
| 
 | ||||
|     private initUserLocationTrail() { | ||||
|         const features = LocalStorageSource.GetParsed<{ feature: any; freshness: Date }[]>( | ||||
|             "gps_location_history", | ||||
|             [] | ||||
|         ) | ||||
|         const now = new Date().getTime() | ||||
|         features.data = features.data | ||||
|             .map((ff) => ({ feature: ff.feature, freshness: new Date(ff.freshness) })) | ||||
|             .filter( | ||||
|                 (ff) => | ||||
|                     now - ff.freshness.getTime() < 1000 * this.gpsLocationHistoryRetentionTime.data | ||||
|             ) | ||||
|         features.ping() | ||||
|         const self = this | ||||
|         let i = 0 | ||||
|         this.currentUserLocation?.features?.addCallbackAndRunD(([location]) => { | ||||
|             if (location === undefined) { | ||||
|                 return | ||||
|             } | ||||
| 
 | ||||
|             const previousLocation = features.data[features.data.length - 1] | ||||
|             if (previousLocation !== undefined) { | ||||
|                 const d = GeoOperations.distanceBetween( | ||||
|                     previousLocation.feature.geometry.coordinates, | ||||
|                     location.feature.geometry.coordinates | ||||
|                 ) | ||||
|                 let timeDiff = Number.MAX_VALUE // in seconds
 | ||||
|                 const olderLocation = features.data[features.data.length - 2] | ||||
|                 if (olderLocation !== undefined) { | ||||
|                     timeDiff = | ||||
|                         (new Date(previousLocation.freshness).getTime() - | ||||
|                             new Date(olderLocation.freshness).getTime()) / | ||||
|                         1000 | ||||
|                 } | ||||
|                 if (d < 20 && timeDiff < 60) { | ||||
|                     // Do not append changes less then 20m - it's probably noise anyway
 | ||||
|                     return | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             const feature = JSON.parse(JSON.stringify(location.feature)) | ||||
|             feature.properties.id = "gps/" + features.data.length | ||||
|             i++ | ||||
|             features.data.push({ feature, freshness: new Date() }) | ||||
|             features.ping() | ||||
|         }) | ||||
| 
 | ||||
|         let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter( | ||||
|             (l) => l.layerDef.id === "gps_location_history" | ||||
|         )[0] | ||||
|         if (gpsLayerDef !== undefined) { | ||||
|             this.historicalUserLocations = new SimpleFeatureSource( | ||||
|                 gpsLayerDef, | ||||
|                 Tiles.tile_index(0, 0, 0), | ||||
|                 features | ||||
|             ) | ||||
|             this.changes.setHistoricalUserLocations(this.historicalUserLocations) | ||||
|         } | ||||
| 
 | ||||
|         const asLine = features.map((allPoints) => { | ||||
|             if (allPoints === undefined || allPoints.length < 2) { | ||||
|                 return [] | ||||
|             } | ||||
| 
 | ||||
|             const feature: Feature<LineString, OsmTags> = { | ||||
|                 type: "Feature", | ||||
|                 properties: { | ||||
|                     id: "location_track", | ||||
|                     "_date:now": new Date().toISOString(), | ||||
|                 }, | ||||
|                 geometry: { | ||||
|                     type: "LineString", | ||||
|                     coordinates: allPoints.map((ff) => ff.feature.geometry.coordinates), | ||||
|                 }, | ||||
|             } | ||||
| 
 | ||||
|             self.allElements.ContainingFeatures.set(feature.properties.id, feature) | ||||
| 
 | ||||
|             return [ | ||||
|                 { | ||||
|                     feature, | ||||
|                     freshness: new Date(), | ||||
|                 }, | ||||
|             ] | ||||
|         }) | ||||
|         let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter( | ||||
|             (l) => l.layerDef.id === "gps_track" | ||||
|         )[0] | ||||
|         if (gpsLineLayerDef !== undefined) { | ||||
|             this.historicalUserLocationsTrack = new TiledStaticFeatureSource( | ||||
|                 asLine, | ||||
|                 gpsLineLayerDef | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private initHomeLocation() { | ||||
|         const empty = [] | ||||
|         const feature = Stores.ListStabilized( | ||||
|             this.osmConnection.userDetails.map((userDetails) => { | ||||
|                 if (userDetails === undefined) { | ||||
|                     return undefined | ||||
|                 } | ||||
|                 const home = userDetails.home | ||||
|                 if (home === undefined) { | ||||
|                     return undefined | ||||
|                 } | ||||
|                 return [home.lon, home.lat] | ||||
|             }) | ||||
|         ).map((homeLonLat) => { | ||||
|             if (homeLonLat === undefined) { | ||||
|                 return empty | ||||
|             } | ||||
|             return [ | ||||
|                 { | ||||
|                     feature: { | ||||
|                         type: "Feature", | ||||
|                         properties: { | ||||
|                             id: "home", | ||||
|                             "user:home": "yes", | ||||
|                             _lon: homeLonLat[0], | ||||
|                             _lat: homeLonLat[1], | ||||
|                         }, | ||||
|                         geometry: { | ||||
|                             type: "Point", | ||||
|                             coordinates: homeLonLat, | ||||
|                         }, | ||||
|                     }, | ||||
|                     freshness: new Date(), | ||||
|                 }, | ||||
|             ] | ||||
|         }) | ||||
| 
 | ||||
|         const flayer = this.filteredLayers.data.filter((l) => l.layerDef.id === "home_location")[0] | ||||
|         if (flayer !== undefined) { | ||||
|             this.homeLocation = new TiledStaticFeatureSource(feature, flayer) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static getPref( | ||||
|         osmConnection: OsmConnection, | ||||
|         key: string, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue