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
2023-03-22 16:25:24 +01:00
// For some weird reason, the 'Object.keys' method doesn't work for the 'location: GeolocationCoordinates'-object and will thus not copy all the properties when using {...location}
// As such, they are copied here
const keysToCopy = [ "speed" , "accuracy" , "altitude" , "altitudeAccuracy" , "heading" ]
2022-12-23 15:52:22 +01:00
this . geolocationState . currentGPSLocation . addCallbackAndRun ( ( location ) = > {
if ( location === undefined ) {
return
}
2023-03-22 16:25:24 +01:00
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 ] ,
} ,
}
2023-03-22 16:25:24 +01:00
for ( const key of keysToCopy ) {
if ( location [ key ] !== null ) {
feature . properties [ key ] = location [ key ]
}
}
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
}