Zoom to geolocation automatically if within 60 seconds, fix reading the previous map location from local storage if not initialized, fix #724"
This commit is contained in:
parent
0cb306e542
commit
49f26687e3
3 changed files with 72 additions and 38 deletions
|
@ -6,6 +6,7 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
|
|||
import {QueryParameters} from "../Web/QueryParameters";
|
||||
import FeatureSource from "../FeatureSource/FeatureSource";
|
||||
import {BBox} from "../BBox";
|
||||
import Constants from "../../Models/Constants";
|
||||
|
||||
export interface GeoLocationPointProperties {
|
||||
id: "gps",
|
||||
|
@ -25,13 +26,11 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
|
||||
/**
|
||||
* Wether or not the geolocation is active, aka the user requested the current location
|
||||
* @private
|
||||
*/
|
||||
private readonly _isActive: UIEventSource<boolean>;
|
||||
|
||||
/**
|
||||
* Wether or not the geolocation is locked, aka the user requested the current location and wants the crosshair to follow the user
|
||||
* @private
|
||||
*/
|
||||
private readonly _isLocked: UIEventSource<boolean>;
|
||||
|
||||
|
@ -54,9 +53,8 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
|
||||
/**
|
||||
* The date when the user requested the geolocation. If we have a location, it'll autozoom to it the first 30 secs
|
||||
* @private
|
||||
*/
|
||||
private _lastUserRequest: Date;
|
||||
private _lastUserRequest: UIEventSource<Date>;
|
||||
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
|
@ -80,6 +78,8 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
) {
|
||||
const currentGPSLocation = new UIEventSource<Coordinates>(undefined, "GPS-coordinate")
|
||||
const leafletMap = state.leafletMap
|
||||
const initedAt = new Date()
|
||||
let autozoomDone = false;
|
||||
const hasLocation = currentGPSLocation.map(
|
||||
(location) => location !== undefined
|
||||
);
|
||||
|
@ -97,13 +97,30 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
|
||||
return timeDiff <= 3
|
||||
})
|
||||
|
||||
const latLonGiven = QueryParameters.wasInitialized("lat") && QueryParameters.wasInitialized("lon")
|
||||
const willFocus = lastClick.map(lastUserRequest => {
|
||||
const timeDiffInited = (new Date().getTime() - initedAt.getTime()) / 1000
|
||||
console.log("TimeDiff with initedAtt is ", timeDiffInited)
|
||||
if (!latLonGiven && !autozoomDone && timeDiffInited < Constants.zoomToLocationTimeout) {
|
||||
return true
|
||||
}
|
||||
if (lastUserRequest === undefined) {
|
||||
return false;
|
||||
}
|
||||
const timeDiff = (new Date().getTime() - lastUserRequest.getTime()) / 1000
|
||||
console.log("TimeDiff with lastClick is ", timeDiff)
|
||||
return timeDiff <= Constants.zoomToLocationTimeout
|
||||
})
|
||||
|
||||
lastClick.addCallbackAndRunD(_ => {
|
||||
window.setTimeout(() => {
|
||||
if (lastClickWithinThreeSecs.data) {
|
||||
if (lastClickWithinThreeSecs.data || willFocus.data) {
|
||||
lastClick.ping()
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
|
||||
super(
|
||||
hasLocation.map(
|
||||
(hasLocationData) => {
|
||||
|
@ -116,7 +133,8 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
}
|
||||
if (!hasLocationData) {
|
||||
// Position not yet found but we are active: we spin to indicate activity
|
||||
const icon = Svg.location_empty_svg()
|
||||
// If will focus is active too, we indicate this differently
|
||||
const icon = willFocus.data ? Svg.location_svg() : Svg.location_empty_svg()
|
||||
icon.SetStyle("animation: spin 4s linear infinite;")
|
||||
return icon;
|
||||
}
|
||||
|
@ -130,7 +148,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
// We have a location, so we show a dot in the center
|
||||
return Svg.location_svg();
|
||||
},
|
||||
[isActive, isLocked, permission, lastClickWithinThreeSecs]
|
||||
[isActive, isLocked, permission, lastClickWithinThreeSecs, willFocus]
|
||||
)
|
||||
);
|
||||
this.SetClass("mapcontrol")
|
||||
|
@ -142,6 +160,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
this._leafletMap = leafletMap;
|
||||
this._layoutToUse = state.layoutToUse;
|
||||
this._hasLocation = hasLocation;
|
||||
this._lastUserRequest = lastClick
|
||||
const self = this;
|
||||
|
||||
const currentPointer = this._isActive.map(
|
||||
|
@ -183,8 +202,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
self.init(true, true);
|
||||
});
|
||||
|
||||
const latLonGiven = QueryParameters.wasInitialized("lat") && QueryParameters.wasInitialized("lon")
|
||||
|
||||
|
||||
const doAutoZoomToLocation = !latLonGiven && state.featureSwitchGeolocation.data && state.selectedElement.data !== undefined
|
||||
this.init(false, doAutoZoomToLocation);
|
||||
|
||||
|
@ -221,8 +239,12 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
self.currentLocation?.features?.setData([{feature, freshness: new Date()}])
|
||||
|
||||
const timeSinceRequest =
|
||||
(new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000;
|
||||
if (timeSinceRequest < 30) {
|
||||
(new Date().getTime() - (self._lastUserRequest.data?.getTime() ?? 0)) / 1000;
|
||||
|
||||
if (willFocus.data) {
|
||||
console.log("Zooming to user location: willFocus is set")
|
||||
willFocus.setData(false)
|
||||
autozoomDone = true;
|
||||
self.MoveToCurrentLocation(16);
|
||||
} else if (self._isLocked.data) {
|
||||
self.MoveToCurrentLocation();
|
||||
|
@ -239,8 +261,8 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
self.MoveToCurrentLocation(16);
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof navigator === "undefined"){
|
||||
|
||||
if (typeof navigator === "undefined") {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -271,7 +293,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
|
||||
/**
|
||||
* Moves to the currently loaded location.
|
||||
*
|
||||
*
|
||||
* // Should move to any location
|
||||
* let resultingLocation = undefined
|
||||
* let resultingzoom = 1
|
||||
|
@ -321,7 +343,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
*/
|
||||
private MoveToCurrentLocation(targetZoom?: number) {
|
||||
const location = this._currentGPSLocation.data;
|
||||
this._lastUserRequest = undefined;
|
||||
this._lastUserRequest.setData(undefined);
|
||||
|
||||
if (
|
||||
this._currentGPSLocation.data.latitude === 0 &&
|
||||
|
@ -356,7 +378,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
private StartGeolocating(zoomToGPS = true) {
|
||||
const self = this;
|
||||
|
||||
this._lastUserRequest = zoomToGPS ? new Date() : new Date(0);
|
||||
this._lastUserRequest.setData(zoomToGPS ? new Date() : new Date(0))
|
||||
if (self._permission.data === "denied") {
|
||||
self._previousLocationGrant.setData("");
|
||||
self._isActive.setData(false)
|
||||
|
|
|
@ -43,29 +43,34 @@ export default class ElementsState extends FeatureSwitchState {
|
|||
|
||||
constructor(layoutToUse: LayoutConfig) {
|
||||
super(layoutToUse);
|
||||
|
||||
|
||||
function localStorageSynced(key: string, deflt: number, docs: string ): UIEventSource<number>{
|
||||
const localStorage = LocalStorageSource.Get(key)
|
||||
const previousValue = localStorage.data
|
||||
const src = UIEventSource.asFloat(
|
||||
QueryParameters.GetQueryParameter(
|
||||
key,
|
||||
"" + deflt,
|
||||
docs
|
||||
).syncWith(localStorage)
|
||||
);
|
||||
|
||||
if(src.data === deflt){
|
||||
const prev = Number(previousValue)
|
||||
if(!isNaN(prev)){
|
||||
src.setData(prev)
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
// -- Location control initialization
|
||||
const zoom = UIEventSource.asFloat(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"z",
|
||||
"" + (layoutToUse?.startZoom ?? 1),
|
||||
"The initial/current zoom level"
|
||||
).syncWith(LocalStorageSource.Get("zoom"))
|
||||
);
|
||||
const lat = UIEventSource.asFloat(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"lat",
|
||||
"" + (layoutToUse?.startLat ?? 0),
|
||||
"The initial/current latitude"
|
||||
).syncWith(LocalStorageSource.Get("lat"))
|
||||
);
|
||||
const lon = UIEventSource.asFloat(
|
||||
QueryParameters.GetQueryParameter(
|
||||
"lon",
|
||||
"" + (layoutToUse?.startLon ?? 0),
|
||||
"The initial/current longitude of the app"
|
||||
).syncWith(LocalStorageSource.Get("lon"))
|
||||
);
|
||||
const zoom = localStorageSynced("z",(layoutToUse?.startZoom ?? 1),"The initial/current zoom level")
|
||||
const lat = localStorageSynced("lat",(layoutToUse?.startLat ?? 0),"The initial/current latitude")
|
||||
const lon = localStorageSynced("lon",(layoutToUse?.startLon ?? 0),"The initial/current longitude of the app")
|
||||
|
||||
|
||||
this.locationControl.setData({
|
||||
zoom: Utils.asFloat(zoom.data),
|
||||
|
@ -73,7 +78,7 @@ export default class ElementsState extends FeatureSwitchState {
|
|||
lon: Utils.asFloat(lon.data),
|
||||
})
|
||||
this.locationControl.addCallback((latlonz) => {
|
||||
// Sync th location controls
|
||||
// Sync the location controls
|
||||
zoom.setData(latlonz.zoom);
|
||||
lat.setData(latlonz.lat);
|
||||
lon.setData(latlonz.lon);
|
||||
|
|
|
@ -62,6 +62,13 @@ export default class Constants {
|
|||
*/
|
||||
static distanceToChangeObjectBins = [25, 50, 100, 500, 1000, 5000, Number.MAX_VALUE]
|
||||
static themeOrder = ["personal", "cyclofix", "waste" , "etymology", "food","cafes_and_pubs", "playgrounds", "hailhydrant", "toilets", "aed", "bookcases"];
|
||||
/**
|
||||
* Upon initialization, the GPS will search the location.
|
||||
* If the location is found within the given timout, it'll automatically fly to it.
|
||||
*
|
||||
* In seconds
|
||||
*/
|
||||
static zoomToLocationTimeout = 60;
|
||||
|
||||
private static isRetina(): boolean {
|
||||
if (Utils.runningFromConsole) {
|
||||
|
|
Loading…
Reference in a new issue