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(