| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | import UserRelatedState from "./UserRelatedState"; | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  | import {Store, Stores, UIEventSource} from "../UIEventSource"; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | import BaseLayer from "../../Models/BaseLayer"; | 
					
						
							|  |  |  | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; | 
					
						
							|  |  |  | import AvailableBaseLayers from "../Actors/AvailableBaseLayers"; | 
					
						
							|  |  |  | import Attribution from "../../UI/BigComponents/Attribution"; | 
					
						
							|  |  |  | import Minimap, {MinimapObj} from "../../UI/Base/Minimap"; | 
					
						
							|  |  |  | import {Tiles} from "../../Models/TileRange"; | 
					
						
							|  |  |  | import BaseUIElement from "../../UI/BaseUIElement"; | 
					
						
							| 
									
										
										
										
											2022-01-08 04:22:50 +01:00
										 |  |  | import FilteredLayer, {FilterState} from "../../Models/FilteredLayer"; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | import TilesourceConfig from "../../Models/ThemeConfig/TilesourceConfig"; | 
					
						
							|  |  |  | import {QueryParameters} from "../Web/QueryParameters"; | 
					
						
							|  |  |  | import ShowOverlayLayer from "../../UI/ShowDataLayer/ShowOverlayLayer"; | 
					
						
							| 
									
										
										
										
											2021-11-09 01:49:07 +01:00
										 |  |  | import {FeatureSourceForLayer, Tiled} from "../FeatureSource/FeatureSource"; | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"; | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  | import {LocalStorageSource} from "../Web/LocalStorageSource"; | 
					
						
							|  |  |  | import {GeoOperations} from "../GeoOperations"; | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | import TitleHandler from "../Actors/TitleHandler"; | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  | import {BBox} from "../BBox"; | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  | import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  | import {TiledStaticFeatureSource} from "../FeatureSource/Sources/StaticFeatureSource"; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Contains all the leaflet-map related state | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export default class MapState extends UserRelatedState { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      The leaflet instance of the big basemap | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-10-15 14:52:11 +02:00
										 |  |  |     public leafletMap = new UIEventSource<any /*L.Map*/>(undefined, "leafletmap"); | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * A list of currently available background layers | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     public availableBackgroundLayers: Store<BaseLayer[]>; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The current background layer | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public backgroundLayer: UIEventSource<BaseLayer>; | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Last location where a click was registered | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public readonly LastClickLocation: UIEventSource<{ | 
					
						
							|  |  |  |         lat: number; | 
					
						
							|  |  |  |         lon: number; | 
					
						
							|  |  |  |     }> = new UIEventSource<{ lat: number; lon: number }>(undefined); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The bounds of the current map view | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public currentView: FeatureSourceForLayer & Tiled; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * The location as delivered by the GPS | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     public currentUserLocation: SimpleFeatureSource; | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * All previously visited points | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |     public historicalUserLocations: SimpleFeatureSource; | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-11-14 16:57:14 +01:00
										 |  |  |      * The number of seconds that the GPS-locations are stored in memory. | 
					
						
							|  |  |  |      * Time in seconds | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |     public gpsLocationHistoryRetentionTime = new UIEventSource(7 * 24 * 60 * 60, "gps_location_retention") | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |     public historicalUserLocationsTrack: FeatureSourceForLayer & Tiled; | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * A feature source containing the current home location of the user | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public homeLocation: FeatureSourceForLayer & Tiled | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public readonly mainMapObject: BaseUIElement & MinimapObj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  |      * Which layers are enabled in the current theme and what filters are applied onto them | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers"); | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Which overlays are shown | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public overlayToggles: { config: TilesourceConfig, isDisplayed: UIEventSource<boolean> }[] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |     constructor(layoutToUse: LayoutConfig, options?: { attemptLogin: true | boolean }) { | 
					
						
							| 
									
										
										
										
											2021-12-13 02:05:34 +01:00
										 |  |  |         super(layoutToUse, options); | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(this.locationControl); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-21 02:44:35 +01:00
										 |  |  |         let defaultLayer = AvailableBaseLayers.osmCarto | 
					
						
							|  |  |  |         const available = this.availableBackgroundLayers.data; | 
					
						
							|  |  |  |         for (const layer of available) { | 
					
						
							|  |  |  |             if (this.backgroundLayerId.data === layer.id) { | 
					
						
							|  |  |  |                 defaultLayer = layer; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const self = this | 
					
						
							|  |  |  |         this.backgroundLayer = new UIEventSource<BaseLayer>(defaultLayer) | 
					
						
							|  |  |  |         this.backgroundLayer.addCallbackAndRunD(layer => self.backgroundLayerId.setData(layer.id)) | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         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, | 
					
						
							|  |  |  |             location: this.locationControl, | 
					
						
							|  |  |  |             leafletMap: this.leafletMap, | 
					
						
							|  |  |  |             bounds: this.currentBounds, | 
					
						
							|  |  |  |             attribution: attr, | 
					
						
							|  |  |  |             lastClickLocation: this.LastClickLocation | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:52:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         this.overlayToggles = this.layoutToUse?.tileLayerSources | 
					
						
							|  |  |  |             ?.filter(c => c.name !== undefined) | 
					
						
							|  |  |  |             ?.map(c => ({ | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |             config: c, | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |             isDisplayed: QueryParameters.GetBooleanQueryParameter("overlay-" + c.id, c.defaultState, "Wether or not the overlay " + c.id + " is shown") | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         })) ?? [] | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         this.filteredLayers = this.InitializeFilteredLayers() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 14:52:11 +02:00
										 |  |  |         this.lockBounds() | 
					
						
							|  |  |  |         this.AddAllOverlaysToMap(this.leafletMap) | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |         this.initHomeLocation() | 
					
						
							|  |  |  |         this.initGpsLocation() | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |         this.initUserLocationTrail() | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |         this.initCurrentView() | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         new TitleHandler(this); | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     public AddAllOverlaysToMap(leafletMap: UIEventSource<any>) { | 
					
						
							|  |  |  |         const initialized = new Set() | 
					
						
							|  |  |  |         for (const overlayToggle of this.overlayToggles) { | 
					
						
							|  |  |  |             new ShowOverlayLayer(overlayToggle.config, leafletMap, overlayToggle.isDisplayed) | 
					
						
							|  |  |  |             initialized.add(overlayToggle.config) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         for (const tileLayerSource of this.layoutToUse?.tileLayerSources ?? []) { | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |             if (initialized.has(tileLayerSource)) { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             new ShowOverlayLayer(tileLayerSource, leafletMap) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private lockBounds() { | 
					
						
							|  |  |  |         const layout = this.layoutToUse; | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         if (!layout?.lockLocation) { | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         console.warn("Locking the bounds to ", layout.lockLocation); | 
					
						
							|  |  |  |         this.mainMapObject.installBounds( | 
					
						
							|  |  |  |             new BBox(layout.lockLocation), | 
					
						
							|  |  |  |             this.featureSwitchIsTesting.data | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initCurrentView() { | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |         let currentViewLayer: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "current_view")[0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         if (currentViewLayer === undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |             // This layer is not needed by the theme and thus unloaded
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let i = 0 | 
					
						
							| 
									
										
										
										
											2021-12-12 02:59:24 +01:00
										 |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |         const features: Store<{ feature: any, freshness: Date }[]> = this.currentBounds.map(bounds => { | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |             if (bounds === undefined) { | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |                 return [] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             i++ | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |             const feature = { | 
					
						
							|  |  |  |                 freshness: new Date(), | 
					
						
							|  |  |  |                 feature: { | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |                     type: "Feature", | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |                     properties: { | 
					
						
							|  |  |  |                         id: "current_view-" + i, | 
					
						
							|  |  |  |                         "current_view": "yes", | 
					
						
							|  |  |  |                         "zoom": "" + self.locationControl.data.zoom | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |                     geometry: { | 
					
						
							|  |  |  |                         type: "Polygon", | 
					
						
							|  |  |  |                         coordinates: [[ | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |                             [bounds.maxLon, bounds.maxLat], | 
					
						
							|  |  |  |                             [bounds.minLon, bounds.maxLat], | 
					
						
							|  |  |  |                             [bounds.minLon, bounds.minLat], | 
					
						
							|  |  |  |                             [bounds.maxLon, bounds.minLat], | 
					
						
							|  |  |  |                             [bounds.maxLon, bounds.maxLat], | 
					
						
							| 
									
										
										
										
											2021-12-10 17:30:50 +01:00
										 |  |  |                         ]] | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return [feature] | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |         this.currentView = new TiledStaticFeatureSource(features,  currentViewLayer); | 
					
						
							| 
									
										
										
										
											2021-12-10 15:51:08 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initGpsLocation() { | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |         // Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
 | 
					
						
							|  |  |  |         let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location")[0] | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         if (gpsLayerDef === undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |         this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initUserLocationTrail() { | 
					
						
							|  |  |  |         const features = LocalStorageSource.GetParsed<{ feature: any, freshness: Date }[]>("gps_location_history", []) | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |         const now = new Date().getTime() | 
					
						
							|  |  |  |         features.data = features.data | 
					
						
							|  |  |  |             .map(ff => ({feature: ff.feature, freshness: new Date(ff.freshness)})) | 
					
						
							| 
									
										
										
										
											2021-11-14 16:57:14 +01:00
										 |  |  |             .filter(ff => (now - ff.freshness.getTime()) < 1000 * this.gpsLocationHistoryRetentionTime.data) | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |         features.ping() | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |         let i = 0 | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         this.currentUserLocation?.features?.addCallbackAndRunD(([location]) => { | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |             if (location === undefined) { | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             const previousLocation = features.data[features.data.length - 1] | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |             if (previousLocation !== undefined) { | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |                 const d = GeoOperations.distanceBetween( | 
					
						
							|  |  |  |                     previousLocation.feature.geometry.coordinates, | 
					
						
							|  |  |  |                     location.feature.geometry.coordinates | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 let timeDiff = Number.MAX_VALUE // in seconds
 | 
					
						
							|  |  |  |                 const olderLocation = features.data[features.data.length - 2] | 
					
						
							|  |  |  |                 if (olderLocation !== undefined) { | 
					
						
							| 
									
										
										
										
											2021-11-15 11:51:32 +01:00
										 |  |  |                     timeDiff = (new Date(previousLocation.freshness).getTime() - new Date(olderLocation.freshness).getTime()) / 1000 | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 if (d < 20 && timeDiff < 60) { | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |                     // Do not append changes less then 20m - it's probably noise anyway
 | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             const feature = JSON.parse(JSON.stringify(location.feature)) | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |             feature.properties.id = "gps/" + features.data.length | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             i++ | 
					
						
							|  |  |  |             features.data.push({feature, freshness: new Date()}) | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |             features.ping() | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |         let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0] | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         if (gpsLayerDef !== undefined) { | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |             this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features); | 
					
						
							| 
									
										
										
										
											2022-02-16 01:46:55 +01:00
										 |  |  |             this.changes.setHistoricalUserLocations(this.historicalUserLocations) | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const asLine = features.map(allPoints => { | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |             if (allPoints === undefined || allPoints.length < 2) { | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |                 return [] | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const feature = { | 
					
						
							|  |  |  |                 type: "Feature", | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 properties: { | 
					
						
							|  |  |  |                     "id": "location_track", | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |                     "_date:now": new Date().toISOString(), | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                 geometry: { | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |                     type: "LineString", | 
					
						
							|  |  |  |                     coordinates: allPoints.map(ff => ff.feature.geometry.coordinates) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             self.allElements.ContainingFeatures.set(feature.properties.id, feature) | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 04:11:53 +01:00
										 |  |  |             return [{ | 
					
						
							|  |  |  |                 feature, | 
					
						
							|  |  |  |                 freshness: new Date() | 
					
						
							|  |  |  |             }] | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         let gpsLineLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_track")[0] | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |         if (gpsLineLayerDef !== undefined) { | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |             this.historicalUserLocationsTrack = new TiledStaticFeatureSource(asLine, gpsLineLayerDef); | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-08 14:18:45 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private initHomeLocation() { | 
					
						
							|  |  |  |         const empty = [] | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |         const feature = Stores.ListStabilized(this.osmConnection.userDetails.map(userDetails => { | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             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": { | 
					
						
							| 
									
										
										
										
											2021-11-12 18:39:38 +01:00
										 |  |  |                         "id": "home", | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |                         "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] | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         if (flayer !== undefined) { | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |             this.homeLocation = new TiledStaticFeatureSource(feature, flayer) | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-15 14:52:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |     private getPref(key: string, layer: LayerConfig): UIEventSource<boolean> { | 
					
						
							|  |  |  |       const pref = this.osmConnection | 
					
						
							|  |  |  |             .GetPreference(key) | 
					
						
							| 
									
										
										
										
											2022-06-05 02:24:14 +02:00
										 |  |  |             .sync(v => { | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |                 if(v === undefined){ | 
					
						
							|  |  |  |                     return undefined | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return v === "true"; | 
					
						
							|  |  |  |             }, [], b => { | 
					
						
							|  |  |  |                 if(b === undefined){ | 
					
						
							|  |  |  |                     return undefined | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return "" + b; | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |         pref.setData(layer.shownByDefault) | 
					
						
							|  |  |  |         return pref | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |     private InitializeFilteredLayers() { | 
					
						
							|  |  |  |         const layoutToUse = this.layoutToUse; | 
					
						
							| 
									
										
										
										
											2022-02-22 14:13:41 +01:00
										 |  |  |         if(layoutToUse === undefined){ | 
					
						
							|  |  |  |             return new UIEventSource<FilteredLayer[]>([]) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         const flayers: FilteredLayer[] = []; | 
					
						
							|  |  |  |         for (const layer of layoutToUse.layers) { | 
					
						
							|  |  |  |             let isDisplayed: UIEventSource<boolean> | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |             if (layer.syncSelection === "local") { | 
					
						
							|  |  |  |                 isDisplayed = LocalStorageSource.GetParsed(layoutToUse.id + "-layer-" + layer.id + "-enabled", layer.shownByDefault) | 
					
						
							|  |  |  |             } else if (layer.syncSelection === "theme-only") { | 
					
						
							|  |  |  |                 isDisplayed = this.getPref(layoutToUse.id+ "-layer-" + layer.id + "-enabled", layer) | 
					
						
							|  |  |  |             } else if (layer.syncSelection === "global") { | 
					
						
							|  |  |  |                 isDisplayed = this.getPref("layer-" + layer.id + "-enabled", layer) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2022-02-16 00:21:03 +01:00
										 |  |  |                 isDisplayed = QueryParameters.GetBooleanQueryParameter("layer-" + layer.id, layer.shownByDefault, "Wether or not layer "+layer.id+" is shown") | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |             const flayer: FilteredLayer = { | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |                 isDisplayed: isDisplayed, | 
					
						
							|  |  |  |                 layerDef: layer, | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  |                 appliedFilters: new UIEventSource<Map<string, FilterState>>(new Map<string, FilterState>()) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |             }; | 
					
						
							| 
									
										
										
										
											2022-01-08 04:22:50 +01:00
										 |  |  |             layer.filters.forEach(filterConfig => { | 
					
						
							|  |  |  |                 const stateSrc = filterConfig.initState() | 
					
						
							| 
									
										
										
										
											2022-01-08 22:11:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 stateSrc.addCallbackAndRun(state => flayer.appliedFilters.data.set(filterConfig.id, state)) | 
					
						
							| 
									
										
										
										
											2022-01-08 04:22:50 +01:00
										 |  |  |                 flayer.appliedFilters.map(dict => dict.get(filterConfig.id)) | 
					
						
							|  |  |  |                     .addCallback(state => stateSrc.setData(state)) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             flayers.push(flayer); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (const layer of layoutToUse.layers) { | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |             if (layer.filterIsSameAs === undefined) { | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             const toReuse = flayers.find(l => l.layerDef.id === layer.filterIsSameAs) | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |             if (toReuse === undefined) { | 
					
						
							|  |  |  |                 throw "Error in layer " + layer.id + ": it defines that it should be use the filters of " + layer.filterIsSameAs + ", but this layer was not loaded" | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  |             console.warn("Linking filter and isDisplayed-states of " + layer.id + " and " + layer.filterIsSameAs) | 
					
						
							| 
									
										
										
										
											2022-02-01 04:14:54 +01:00
										 |  |  |             const selfLayer = flayers.findIndex(l => l.layerDef.id === layer.id) | 
					
						
							|  |  |  |             flayers[selfLayer] = { | 
					
						
							|  |  |  |                 isDisplayed: toReuse.isDisplayed, | 
					
						
							|  |  |  |                 layerDef: layer, | 
					
						
							|  |  |  |                 appliedFilters: toReuse.appliedFilters | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-14 18:18:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-15 05:20:02 +02:00
										 |  |  |         return new UIEventSource<FilteredLayer[]>(flayers); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |