diff --git a/debug/multiple.html b/debug/multiple.html
index 342bc774a9f..6c279c00b7c 100644
--- a/debug/multiple.html
+++ b/debug/multiple.html
@@ -63,6 +63,17 @@
style,
hash: false
});
+
+ map.addControl(new mapboxgl.GeolocateControl({
+ positionOptions: {
+ enableHighAccuracy: true
+ },
+ trackUserLocation: true,
+ showUserLocation: true,
+ fitBoundsOptions: {
+ maxZoom: 20
+ }
+ }));
}
var containers = document.querySelectorAll('.map');
diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js
index 0f9a0e6a894..d9b024753c2 100644
--- a/src/ui/control/geolocate_control.js
+++ b/src/ui/control/geolocate_control.js
@@ -53,6 +53,9 @@ function checkGeolocationSupport(callback) {
}
}
+let numberOfWatches = 0;
+let noTimeout = false;
+
/**
* A `GeolocateControl` control provides a button that uses the browser's geolocation
* API to locate the user on the map.
@@ -134,6 +137,8 @@ class GeolocateControl extends Evented {
DOM.remove(this._container);
this._map = (undefined: any);
+ numberOfWatches = 0;
+ noTimeout = false;
}
_isOutOfMapMaxBounds(position: Position) {
@@ -270,6 +275,12 @@ class GeolocateControl extends Evented {
if (this._geolocationWatchID !== undefined) {
this._clearWatch();
}
+ } else if (error.code === 3 && noTimeout) {
+ // this represents a forced error state
+ // this was triggered to force immediate geolocation when a watch is already present
+ // see https://github.com/mapbox/mapbox-gl-js/issues/8214
+ // and https://w3c.github.io/geolocation-api/#example-5-forcing-the-user-agent-to-return-a-fresh-cached-position
+ return;
} else {
this._setErrorState();
}
@@ -366,6 +377,8 @@ class GeolocateControl extends Evented {
case 'ACTIVE_ERROR':
case 'BACKGROUND_ERROR':
// turn off the Geolocate Control
+ numberOfWatches--;
+ noTimeout = false;
this._watchState = 'OFF';
this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
@@ -423,8 +436,18 @@ class GeolocateControl extends Evented {
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
this._geolocateButton.setAttribute('aria-pressed', 'true');
+ numberOfWatches++;
+ let positionOptions;
+ if (numberOfWatches > 1) {
+ positionOptions = {maximumAge:600000, timeout:0};
+ noTimeout = true;
+ } else {
+ positionOptions = this.options.positionOptions;
+ noTimeout = false;
+ }
+
this._geolocationWatchID = window.navigator.geolocation.watchPosition(
- this._onSuccess, this._onError, this.options.positionOptions);
+ this._onSuccess, this._onError, positionOptions);
}
} else {
window.navigator.geolocation.getCurrentPosition(