| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | import { QueryParameters } from "../Web/QueryParameters" | 
					
						
							|  |  |  | import { BBox } from "../BBox" | 
					
						
							|  |  |  | import Constants from "../../Models/Constants" | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | import { GeoLocationPointProperties, GeoLocationState } from "../State/GeoLocationState" | 
					
						
							|  |  |  | import { UIEventSource } from "../UIEventSource" | 
					
						
							| 
									
										
										
										
											2023-01-29 13:10:57 +01:00
										 |  |  | import Loc from "../../Models/Loc" | 
					
						
							|  |  |  | import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig" | 
					
						
							|  |  |  | import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource" | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * The geolocation-handler takes a map-location and a geolocation state. | 
					
						
							|  |  |  |  * It'll move the map as appropriate given the state of the geolocation-API | 
					
						
							| 
									
										
										
										
											2022-12-23 15:52:22 +01:00
										 |  |  |  * It will also copy the geolocation into the appropriate FeatureSource to display on the map | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | export default class GeoLocationHandler { | 
					
						
							|  |  |  |     public readonly geolocationState: GeoLocationState | 
					
						
							| 
									
										
										
										
											2023-01-29 13:10:57 +01:00
										 |  |  |     private readonly _state: { | 
					
						
							|  |  |  |         currentUserLocation: SimpleFeatureSource | 
					
						
							|  |  |  |         layoutToUse: LayoutConfig | 
					
						
							|  |  |  |         locationControl: UIEventSource<Loc> | 
					
						
							|  |  |  |         selectedElement: UIEventSource<any> | 
					
						
							|  |  |  |         leafletMap?: UIEventSource<any> | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     public readonly mapHasMoved: UIEventSource<boolean> = new UIEventSource<boolean>(false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         geolocationState: GeoLocationState, | 
					
						
							| 
									
										
										
										
											2023-01-29 13:10:57 +01:00
										 |  |  |         state: { | 
					
						
							|  |  |  |             locationControl: UIEventSource<Loc> | 
					
						
							|  |  |  |             currentUserLocation: SimpleFeatureSource | 
					
						
							|  |  |  |             layoutToUse: LayoutConfig | 
					
						
							|  |  |  |             selectedElement: UIEventSource<any> | 
					
						
							|  |  |  |             leafletMap?: UIEventSource<any> | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     ) { | 
					
						
							|  |  |  |         this.geolocationState = geolocationState | 
					
						
							|  |  |  |         this._state = state | 
					
						
							|  |  |  |         const mapLocation = state.locationControl | 
					
						
							|  |  |  |         // Did an interaction move the map?
 | 
					
						
							|  |  |  |         let self = this | 
					
						
							|  |  |  |         let initTime = new Date() | 
					
						
							|  |  |  |         mapLocation.addCallbackD((_) => { | 
					
						
							|  |  |  |             if (new Date().getTime() - initTime.getTime() < 250) { | 
					
						
							|  |  |  |                 return | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             self.mapHasMoved.setData(true) | 
					
						
							|  |  |  |             return true // Unsubscribe
 | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-04-09 19:29:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         const latLonGivenViaUrl = | 
					
						
							|  |  |  |             QueryParameters.wasInitialized("lat") || QueryParameters.wasInitialized("lon") | 
					
						
							|  |  |  |         if (latLonGivenViaUrl) { | 
					
						
							|  |  |  |             // The URL counts as a 'user interaction'
 | 
					
						
							|  |  |  |             this.mapHasMoved.setData(true) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-04-09 19:29:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         this.geolocationState.currentGPSLocation.addCallbackAndRunD((newLocation) => { | 
					
						
							|  |  |  |             const timeSinceLastRequest = | 
					
						
							|  |  |  |                 (new Date().getTime() - geolocationState.requestMoment.data?.getTime() ?? 0) / 1000 | 
					
						
							|  |  |  |             if (!this.mapHasMoved.data) { | 
					
						
							|  |  |  |                 // The map hasn't moved yet; we received our first coordinates, so let's move there!
 | 
					
						
							| 
									
										
										
										
											2023-02-09 03:12:21 +01:00
										 |  |  |                 self.MoveMapToCurrentLocation() | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (timeSinceLastRequest < Constants.zoomToLocationTimeout) { | 
					
						
							|  |  |  |                 self.MoveMapToCurrentLocation() | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-07-19 16:23:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             if (this.geolocationState.isLocked.data) { | 
					
						
							|  |  |  |                 // Jup, the map is locked to the bound location: move automatically
 | 
					
						
							|  |  |  |                 self.MoveMapToCurrentLocation() | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         geolocationState.isLocked.map( | 
					
						
							|  |  |  |             (isLocked) => { | 
					
						
							|  |  |  |                 if (isLocked) { | 
					
						
							|  |  |  |                     state.leafletMap?.data?.dragging?.disable() | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |                     state.leafletMap?.data?.dragging?.enable() | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             }, | 
					
						
							|  |  |  |             [state.leafletMap] | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         this.CopyGeolocationIntoMapstate() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-04-13 01:26:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Move the map to the GPS-location, except: | 
					
						
							|  |  |  |      * - If there is a selected element | 
					
						
							|  |  |  |      * - The location is out of the locked bound | 
					
						
							|  |  |  |      * - The GPS-location iss NULL-island | 
					
						
							|  |  |  |      * @constructor | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public MoveMapToCurrentLocation() { | 
					
						
							|  |  |  |         const newLocation = this.geolocationState.currentGPSLocation.data | 
					
						
							|  |  |  |         const mapLocation = this._state.locationControl | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							|  |  |  |         // We got a new location.
 | 
					
						
							|  |  |  |         // Do we move the map to it?
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (state.selectedElement.data !== undefined) { | 
					
						
							|  |  |  |             // Nope, there is something selected, so we don't move to the current GPS-location
 | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (newLocation.latitude === 0 && newLocation.longitude === 0) { | 
					
						
							|  |  |  |             console.debug("Not moving to GPS-location: it is null island") | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-07-19 16:23:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         // We check that the GPS location is not out of bounds
 | 
					
						
							|  |  |  |         const bounds = state.layoutToUse.lockLocation | 
					
						
							|  |  |  |         if (bounds && bounds !== true) { | 
					
						
							|  |  |  |             // B is an array with our lock-location
 | 
					
						
							|  |  |  |             const inRange = new BBox(bounds).contains([newLocation.longitude, newLocation.latitude]) | 
					
						
							|  |  |  |             if (!inRange) { | 
					
						
							|  |  |  |                 return | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mapLocation.setData({ | 
					
						
							| 
									
										
										
										
											2023-02-09 03:12:21 +01:00
										 |  |  |             zoom: Math.max(mapLocation.data.zoom, 16), | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             lon: newLocation.longitude, | 
					
						
							|  |  |  |             lat: newLocation.latitude, | 
					
						
							| 
									
										
										
										
											2021-08-19 23:41:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |         this.mapHasMoved.setData(true) | 
					
						
							| 
									
										
										
										
											2023-02-09 03:12:21 +01:00
										 |  |  |         this.geolocationState.requestMoment.setData(undefined) | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-09 00:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |     private CopyGeolocationIntoMapstate() { | 
					
						
							|  |  |  |         const state = this._state | 
					
						
							| 
									
										
										
										
											2022-12-23 15:52:22 +01:00
										 |  |  |         this.geolocationState.currentGPSLocation.addCallbackAndRun((location) => { | 
					
						
							|  |  |  |             if (location === undefined) { | 
					
						
							|  |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-03 00:44:53 +01:00
										 |  |  |             const feature = { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 type: "Feature", | 
					
						
							| 
									
										
										
										
											2021-11-09 01:49:07 +01:00
										 |  |  |                 properties: <GeoLocationPointProperties>{ | 
					
						
							| 
									
										
										
										
											2021-11-08 02:36:01 +01:00
										 |  |  |                     id: "gps", | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |                     "user:location": "yes", | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                     date: new Date().toISOString(), | 
					
						
							| 
									
										
										
										
											2022-12-23 14:22:52 +01:00
										 |  |  |                     ...location, | 
					
						
							| 
									
										
										
										
											2021-11-03 00:44:53 +01:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |                 geometry: { | 
					
						
							|  |  |  |                     type: "Point", | 
					
						
							| 
									
										
										
										
											2021-11-03 00:44:53 +01:00
										 |  |  |                     coordinates: [location.longitude, location.latitude], | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2021-11-03 00:44:53 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-22 04:13:52 +01:00
										 |  |  |             state.currentUserLocation?.features?.setData([{ feature, freshness: new Date() }]) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2020-06-28 02:42:22 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-19 16:23:13 +02:00
										 |  |  | } |