Switch to GNSS immediately if it turns on mid-track
If Locate was already tracking via the browser-geolocation fallback (GNSS was off when clicked) and GNSS then gets turned on via the sidebar, it kept using the browser position until the button was clicked again -- the browser's own (often less accurate) position had no business still being used once the app's own receiver had a fix. GnssControl#onEnabledChange (a small internal callback list) notifies LocateControl the moment the sidebar toggle changes; if it's actively tracking via the browser at that point, it stops that and jumps to GNSS's position instead. Caught a real bug while verifying this: the automatic handoff reused the same jump-to-GNSS helper a deliberate click uses, which alerts if GNSS has no fix yet -- but GNSS only just turned on and almost certainly hasn't gotten its first poll response back yet at the exact moment the handoff fires, so this popped a blocking window.alert() (which halts the whole page until dismissed) on every single enable. A test hung on exactly this before I noticed. Fixed with an alertIfNoFix option, true only for the deliberate-click path. Verified end to end (simulating the "already tracking" state directly since headless geolocation isn't reliable enough to trust as the trigger): toggling GNSS mid-track removes the blue browser marker, shows the green GNSS one once its poll lands, and no dialog appears.
This commit is contained in:
1 parent
f0ac8ac5d4
commit
d9879bad60
3 files changed
+63
-10
No files matched your search
@@ -261,6 +261,21 @@ as "the GNSS simulator, leaking somehow"). Uses MapLibre's own blue
|
|||||||
pulsing `.maplibregl-user-location-dot` (`maplibre-gl.css`) instead —
|
pulsing `.maplibregl-user-location-dot` (`maplibre-gl.css`) instead —
|
||||||
the same look GeolocateControl itself had here before, and visually
|
the same look GeolocateControl itself had here before, and visually
|
||||||
distinct from GNSS's green on purpose.
|
distinct from GNSS's green on purpose.
|
||||||
|
+
|
||||||
|
GNSS turning on *while* the browser fallback is already mid-track
|
||||||
|
switches over immediately rather than waiting for another click —
|
||||||
|
`GnssControl#onEnabledChange` (a small internal callback list, not a
|
||||||
|
full pub/sub system — nothing else needs one) notifies `LocateControl`
|
||||||
|
the moment the sidebar toggle changes; if it was actively tracking via
|
||||||
|
the browser at that point, it stops that and jumps to GNSS's position
|
||||||
|
instead. That jump doesn't alert if GNSS has no fix yet (a
|
||||||
|
`{ alertIfNoFix }` option on the shared jump-to-GNSS helper, `true`
|
||||||
|
only for a deliberate click) — `GnssControl` only just turned on and
|
||||||
|
almost certainly hasn't gotten its first poll response back yet at
|
||||||
|
the exact moment this fires, so alerting here would pop a blocking
|
||||||
|
dialog (window.alert() halts the whole page until dismissed) on every
|
||||||
|
single enable; its own next poll shows/recenters once it actually has
|
||||||
|
something, same as it would either way.
|
||||||
|
|
||||||
=== Debug inspector (Alt+click)
|
=== Debug inspector (Alt+click)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ export class GnssControl {
|
|||||||
this._marker = null;
|
this._marker = null;
|
||||||
this._timer = null;
|
this._timer = null;
|
||||||
this._enabled = false;
|
this._enabled = false;
|
||||||
|
this._enabledListeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read by LocateControl: if it's mid-tracking on the browser-geolocation
|
||||||
|
// fallback when GNSS turns on, GNSS should take over there and then, not
|
||||||
|
// only the next time the button happens to get clicked — the browser's
|
||||||
|
// own (often less accurate) position has no business still being used
|
||||||
|
// once the app's own receiver has a fix.
|
||||||
|
onEnabledChange(callback) {
|
||||||
|
this._enabledListeners.push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
mount(sidebar) {
|
mount(sidebar) {
|
||||||
@@ -46,6 +56,7 @@ export class GnssControl {
|
|||||||
this._removeMarker();
|
this._removeMarker();
|
||||||
this._status.textContent = "";
|
this._status.textContent = "";
|
||||||
}
|
}
|
||||||
|
this._enabledListeners.forEach((callback) => callback(enabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
_stopPolling() {
|
_stopPolling() {
|
||||||
|
|||||||
+37
-10
@@ -37,6 +37,25 @@ export class LocateControl {
|
|||||||
this._container = document.createElement("div");
|
this._container = document.createElement("div");
|
||||||
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
|
this._container.className = "maplibregl-ctrl maplibregl-ctrl-group";
|
||||||
this._container.appendChild(this._button);
|
this._container.appendChild(this._button);
|
||||||
|
|
||||||
|
// GNSS turning on mid-track (this control's own browser-geolocation
|
||||||
|
// fallback, not GnssControl's — that one manages its own tracking)
|
||||||
|
// should switch over immediately, not just the next time this button
|
||||||
|
// gets clicked; the browser's own position has no business still
|
||||||
|
// being used once the app's own receiver has a fix. No alertIfNoFix
|
||||||
|
// here (unlike a deliberate click, below) — GnssControl only just
|
||||||
|
// turned on and almost certainly hasn't gotten its first fix back yet
|
||||||
|
// (its own poll is async, still in flight at the moment this fires),
|
||||||
|
// so this would otherwise pop a blocking "waiting for a fix" dialog on
|
||||||
|
// every single enable; GnssControl's own next poll will show/recenter
|
||||||
|
// once it actually has something, same as it would either way.
|
||||||
|
this._gnssControl.onEnabledChange((enabled) => {
|
||||||
|
if (enabled && this._active) {
|
||||||
|
this._stop();
|
||||||
|
this._jumpToGnss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return this._container;
|
return this._container;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,16 +70,7 @@ export class LocateControl {
|
|||||||
|
|
||||||
_click() {
|
_click() {
|
||||||
if (this._gnssControl.isEnabled()) {
|
if (this._gnssControl.isEnabled()) {
|
||||||
// GNSS already follows the map on its own once enabled (GnssControl)
|
this._jumpToGnss({ alertIfNoFix: true });
|
||||||
// and has no separate "off" state to toggle from here — just jump to
|
|
||||||
// its current fix now, for the same instant feedback clicking this
|
|
||||||
// button has always given.
|
|
||||||
const position = this._gnssControl.getPosition();
|
|
||||||
if (position) {
|
|
||||||
this._map.flyTo({ center: position, zoom: Math.max(this._map.getZoom(), 15) });
|
|
||||||
} else {
|
|
||||||
window.alert("Waiting for a GNSS fix…");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +81,23 @@ export class LocateControl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GNSS already follows the map on its own once enabled (GnssControl) and
|
||||||
|
// has no separate "off" state to toggle from here — just jump to its
|
||||||
|
// current fix, for the same instant feedback clicking this button has
|
||||||
|
// always given. alertIfNoFix is opt-in (a deliberate click wants to know
|
||||||
|
// why nothing happened; the automatic mid-track handoff above doesn't —
|
||||||
|
// see its own comment) since a JS alert() blocks the whole page until
|
||||||
|
// dismissed, not something to pop up on a path that isn't a direct user
|
||||||
|
// action.
|
||||||
|
_jumpToGnss({ alertIfNoFix = false } = {}) {
|
||||||
|
const position = this._gnssControl.getPosition();
|
||||||
|
if (position) {
|
||||||
|
this._map.flyTo({ center: position, zoom: Math.max(this._map.getZoom(), 15) });
|
||||||
|
} else if (alertIfNoFix) {
|
||||||
|
window.alert("Waiting for a GNSS fix…");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_start() {
|
_start() {
|
||||||
this._active = true;
|
this._active = true;
|
||||||
this._button.classList.add("maplibregl-ctrl-geolocate-active");
|
this._button.classList.add("maplibregl-ctrl-geolocate-active");
|
||||||
|
|||||||
Reference in new issue
Block a user