2021-08-26 12:15:26 +02:00
|
|
|
import { QueryParameters } from "../Web/QueryParameters"
|
2022-03-28 21:56:25 +02:00
|
|
|
import { BBox } from "../BBox"
|
2022-04-09 19:29:51 +02:00
|
|
|
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
|
|
|
|
}
|
2021-07-23 15:56:22 +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 = {
|
|
|
|
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",
|
2021-11-08 14:18:45 +01: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],
|
|
|
|
},
|
|
|
|
}
|
2021-11-07 16:34:51 +01:00
|
|
|
|
2022-12-22 04:13:52 +01:00
|
|
|
state.currentUserLocation?.features?.setData([{ feature, freshness: new Date() }])
|
2021-07-23 15:56:22 +02:00
|
|
|
})
|
2020-06-28 02:42:22 +02:00
|
|
|
}
|
2021-07-19 16:23:13 +02:00
|
|
|
}
|