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 {QueryParameters} from "../Web/QueryParameters";
|
||||||
import FeatureSource from "../FeatureSource/FeatureSource";
|
import FeatureSource from "../FeatureSource/FeatureSource";
|
||||||
import {BBox} from "../BBox";
|
import {BBox} from "../BBox";
|
||||||
|
import Constants from "../../Models/Constants";
|
||||||
|
|
||||||
export interface GeoLocationPointProperties {
|
export interface GeoLocationPointProperties {
|
||||||
id: "gps",
|
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
|
* Wether or not the geolocation is active, aka the user requested the current location
|
||||||
* @private
|
|
||||||
*/
|
*/
|
||||||
private readonly _isActive: UIEventSource<boolean>;
|
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
|
* 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>;
|
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
|
* 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.
|
* 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 currentGPSLocation = new UIEventSource<Coordinates>(undefined, "GPS-coordinate")
|
||||||
const leafletMap = state.leafletMap
|
const leafletMap = state.leafletMap
|
||||||
|
const initedAt = new Date()
|
||||||
|
let autozoomDone = false;
|
||||||
const hasLocation = currentGPSLocation.map(
|
const hasLocation = currentGPSLocation.map(
|
||||||
(location) => location !== undefined
|
(location) => location !== undefined
|
||||||
);
|
);
|
||||||
|
@ -97,13 +97,30 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
|
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
|
||||||
return timeDiff <= 3
|
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(_ => {
|
lastClick.addCallbackAndRunD(_ => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
if (lastClickWithinThreeSecs.data) {
|
if (lastClickWithinThreeSecs.data || willFocus.data) {
|
||||||
lastClick.ping()
|
lastClick.ping()
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
|
|
||||||
super(
|
super(
|
||||||
hasLocation.map(
|
hasLocation.map(
|
||||||
(hasLocationData) => {
|
(hasLocationData) => {
|
||||||
|
@ -116,7 +133,8 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
}
|
}
|
||||||
if (!hasLocationData) {
|
if (!hasLocationData) {
|
||||||
// Position not yet found but we are active: we spin to indicate activity
|
// 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;")
|
icon.SetStyle("animation: spin 4s linear infinite;")
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +148,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
// We have a location, so we show a dot in the center
|
// We have a location, so we show a dot in the center
|
||||||
return Svg.location_svg();
|
return Svg.location_svg();
|
||||||
},
|
},
|
||||||
[isActive, isLocked, permission, lastClickWithinThreeSecs]
|
[isActive, isLocked, permission, lastClickWithinThreeSecs, willFocus]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.SetClass("mapcontrol")
|
this.SetClass("mapcontrol")
|
||||||
|
@ -142,6 +160,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
this._leafletMap = leafletMap;
|
this._leafletMap = leafletMap;
|
||||||
this._layoutToUse = state.layoutToUse;
|
this._layoutToUse = state.layoutToUse;
|
||||||
this._hasLocation = hasLocation;
|
this._hasLocation = hasLocation;
|
||||||
|
this._lastUserRequest = lastClick
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
const currentPointer = this._isActive.map(
|
const currentPointer = this._isActive.map(
|
||||||
|
@ -183,7 +202,6 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
self.init(true, true);
|
self.init(true, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
const latLonGiven = QueryParameters.wasInitialized("lat") && QueryParameters.wasInitialized("lon")
|
|
||||||
|
|
||||||
const doAutoZoomToLocation = !latLonGiven && state.featureSwitchGeolocation.data && state.selectedElement.data !== undefined
|
const doAutoZoomToLocation = !latLonGiven && state.featureSwitchGeolocation.data && state.selectedElement.data !== undefined
|
||||||
this.init(false, doAutoZoomToLocation);
|
this.init(false, doAutoZoomToLocation);
|
||||||
|
@ -221,8 +239,12 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
self.currentLocation?.features?.setData([{feature, freshness: new Date()}])
|
self.currentLocation?.features?.setData([{feature, freshness: new Date()}])
|
||||||
|
|
||||||
const timeSinceRequest =
|
const timeSinceRequest =
|
||||||
(new Date().getTime() - (self._lastUserRequest?.getTime() ?? 0)) / 1000;
|
(new Date().getTime() - (self._lastUserRequest.data?.getTime() ?? 0)) / 1000;
|
||||||
if (timeSinceRequest < 30) {
|
|
||||||
|
if (willFocus.data) {
|
||||||
|
console.log("Zooming to user location: willFocus is set")
|
||||||
|
willFocus.setData(false)
|
||||||
|
autozoomDone = true;
|
||||||
self.MoveToCurrentLocation(16);
|
self.MoveToCurrentLocation(16);
|
||||||
} else if (self._isLocked.data) {
|
} else if (self._isLocked.data) {
|
||||||
self.MoveToCurrentLocation();
|
self.MoveToCurrentLocation();
|
||||||
|
@ -240,7 +262,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof navigator === "undefined"){
|
if (typeof navigator === "undefined") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +343,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
*/
|
*/
|
||||||
private MoveToCurrentLocation(targetZoom?: number) {
|
private MoveToCurrentLocation(targetZoom?: number) {
|
||||||
const location = this._currentGPSLocation.data;
|
const location = this._currentGPSLocation.data;
|
||||||
this._lastUserRequest = undefined;
|
this._lastUserRequest.setData(undefined);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this._currentGPSLocation.data.latitude === 0 &&
|
this._currentGPSLocation.data.latitude === 0 &&
|
||||||
|
@ -356,7 +378,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
||||||
private StartGeolocating(zoomToGPS = true) {
|
private StartGeolocating(zoomToGPS = true) {
|
||||||
const self = this;
|
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") {
|
if (self._permission.data === "denied") {
|
||||||
self._previousLocationGrant.setData("");
|
self._previousLocationGrant.setData("");
|
||||||
self._isActive.setData(false)
|
self._isActive.setData(false)
|
||||||
|
|
|
@ -44,28 +44,33 @@ export default class ElementsState extends FeatureSwitchState {
|
||||||
constructor(layoutToUse: LayoutConfig) {
|
constructor(layoutToUse: LayoutConfig) {
|
||||||
super(layoutToUse);
|
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
|
// -- Location control initialization
|
||||||
const zoom = UIEventSource.asFloat(
|
const zoom = localStorageSynced("z",(layoutToUse?.startZoom ?? 1),"The initial/current zoom level")
|
||||||
QueryParameters.GetQueryParameter(
|
const lat = localStorageSynced("lat",(layoutToUse?.startLat ?? 0),"The initial/current latitude")
|
||||||
"z",
|
const lon = localStorageSynced("lon",(layoutToUse?.startLon ?? 0),"The initial/current longitude of the app")
|
||||||
"" + (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"))
|
|
||||||
);
|
|
||||||
|
|
||||||
this.locationControl.setData({
|
this.locationControl.setData({
|
||||||
zoom: Utils.asFloat(zoom.data),
|
zoom: Utils.asFloat(zoom.data),
|
||||||
|
@ -73,7 +78,7 @@ export default class ElementsState extends FeatureSwitchState {
|
||||||
lon: Utils.asFloat(lon.data),
|
lon: Utils.asFloat(lon.data),
|
||||||
})
|
})
|
||||||
this.locationControl.addCallback((latlonz) => {
|
this.locationControl.addCallback((latlonz) => {
|
||||||
// Sync th location controls
|
// Sync the location controls
|
||||||
zoom.setData(latlonz.zoom);
|
zoom.setData(latlonz.zoom);
|
||||||
lat.setData(latlonz.lat);
|
lat.setData(latlonz.lat);
|
||||||
lon.setData(latlonz.lon);
|
lon.setData(latlonz.lon);
|
||||||
|
|
|
@ -62,6 +62,13 @@ export default class Constants {
|
||||||
*/
|
*/
|
||||||
static distanceToChangeObjectBins = [25, 50, 100, 500, 1000, 5000, Number.MAX_VALUE]
|
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"];
|
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 {
|
private static isRetina(): boolean {
|
||||||
if (Utils.runningFromConsole) {
|
if (Utils.runningFromConsole) {
|
||||||
|
|
Loading…
Reference in a new issue