From b069b9069ce7922081df128e726d4df98fd7e6ea Mon Sep 17 00:00:00 2001 From: Behnam Mohammadi Date: Mon, 21 Dec 2020 13:49:08 +0330 Subject: [PATCH 1/6] feat: send geolocation as adapter --- src/ui/control/geolocate_control.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 215806c4d46..5708bfd81c5 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -18,7 +18,8 @@ type Options = { trackUserLocation?: boolean, showAccuracyCircle?: boolean, showUserLocation?: boolean, - showUserHeading?: boolean + showUserHeading?: boolean, + geolocation?: Geolocation, }; type DeviceOrientationEvent = { @@ -42,9 +43,12 @@ const defaultOptions: Options = { trackUserLocation: false, showAccuracyCircle: true, showUserLocation: true, - showUserHeading: false + showUserHeading: false, + geolocation: window.navigator.geolocation }; +let geolocation; + let supportsGeolocation; function checkGeolocationSupport(callback) { @@ -62,7 +66,7 @@ function checkGeolocationSupport(callback) { }); } else { - supportsGeolocation = !!window.navigator.geolocation; + supportsGeolocation = !!geolocation; callback(supportsGeolocation); } } @@ -131,6 +135,8 @@ class GeolocateControl extends Evented { super(); this.options = extend({}, defaultOptions, options); + geolocation = this.options.geolocation; + bindAll([ '_onSuccess', '_onError', @@ -156,7 +162,7 @@ class GeolocateControl extends Evented { onRemove() { // clear the geolocation watch if exists if (this._geolocationWatchID !== undefined) { - window.navigator.geolocation.clearWatch(this._geolocationWatchID); + geolocation.clearWatch(this._geolocationWatchID); this._geolocationWatchID = (undefined: any); } @@ -615,7 +621,7 @@ class GeolocateControl extends Evented { noTimeout = false; } - this._geolocationWatchID = window.navigator.geolocation.watchPosition( + this._geolocationWatchID = geolocation.watchPosition( this._onSuccess, this._onError, positionOptions); if (this.options.showUserHeading) { @@ -623,7 +629,7 @@ class GeolocateControl extends Evented { } } } else { - window.navigator.geolocation.getCurrentPosition( + geolocation.getCurrentPosition( this._onSuccess, this._onError, this.options.positionOptions); // This timeout ensures that we still call finish() even if @@ -659,7 +665,7 @@ class GeolocateControl extends Evented { } _clearWatch() { - window.navigator.geolocation.clearWatch(this._geolocationWatchID); + geolocation.clearWatch(this._geolocationWatchID); window.removeEventListener('deviceorientation', this._onDeviceOrientation); window.removeEventListener('deviceorientationabsolute', this._onDeviceOrientation); From 70b25a1d48477a61941ed2eadaf1b9ce8a7db9ff Mon Sep 17 00:00:00 2001 From: Behnam Mohammadi Date: Mon, 21 Dec 2020 16:07:05 +0330 Subject: [PATCH 2/6] fix: instanceable geolocation --- src/ui/control/geolocate_control.js | 82 +++++++++++++---------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 5708bfd81c5..83f2d58cc2b 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -47,33 +47,6 @@ const defaultOptions: Options = { geolocation: window.navigator.geolocation }; -let geolocation; - -let supportsGeolocation; - -function checkGeolocationSupport(callback) { - if (supportsGeolocation !== undefined) { - callback(supportsGeolocation); - - } else if (window.navigator.permissions !== undefined) { - // navigator.permissions has incomplete browser support - // http://caniuse.com/#feat=permissions-api - // Test for the case where a browser disables Geolocation because of an - // insecure origin - window.navigator.permissions.query({name: 'geolocation'}).then((p) => { - supportsGeolocation = p.state !== 'denied'; - callback(supportsGeolocation); - }); - - } else { - supportsGeolocation = !!geolocation; - callback(supportsGeolocation); - } -} - -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. @@ -102,6 +75,7 @@ let noTimeout = false; * @param {Object} [options.showAccuracyCircle=true] By default, if `showUserLocation` is `true`, a transparent circle will be drawn around the user location indicating the accuracy (95% confidence level) of the user's location. Set to `false` to disable. Always disabled when `showUserLocation` is `false`. * @param {Object} [options.showUserLocation=true] By default a dot will be shown on the map at the user's location. Set to `false` to disable. * @param {Object} [options.showUserHeading=false] If `true` an arrow will be drawn next to the user location dot indicating the device's heading. This only has affect when `trackUserLocation` is `true`. + * @param {Object} [options.geolocation=window.navigator.geolocation] By default geolocation uses window.navigator.geolocation but you can customize this object * * @example * map.addControl(new mapboxgl.GeolocateControl({ @@ -131,12 +105,14 @@ class GeolocateControl extends Evented { _heading: ?number; _updateMarkerRotationThrottled: Function; + _numberOfWatches: number = 0; + _noTimeout: boolean = false; + _supportsGeolocation: boolean = false; + constructor(options: Options) { super(); this.options = extend({}, defaultOptions, options); - geolocation = this.options.geolocation; - bindAll([ '_onSuccess', '_onError', @@ -155,14 +131,14 @@ class GeolocateControl extends Evented { onAdd(map: Map): HTMLElement { this._map = map; this._container = DOM.create('div', `mapboxgl-ctrl mapboxgl-ctrl-group`); - checkGeolocationSupport(this._setupUI); + this._checkGeolocationSupport(this._setupUI); return this._container; } onRemove() { // clear the geolocation watch if exists if (this._geolocationWatchID !== undefined) { - geolocation.clearWatch(this._geolocationWatchID); + this.options.geolocation.clearWatch(this._geolocationWatchID); this._geolocationWatchID = (undefined: any); } @@ -177,8 +153,26 @@ class GeolocateControl extends Evented { this._container.remove(); this._map.off('zoom', this._onZoom); this._map = (undefined: any); - numberOfWatches = 0; - noTimeout = false; + this._numberOfWatches = 0; + this._noTimeout = false; + } + + _checkGeolocationSupport(callback) { + if (this._supportsGeolocation !== undefined) { + callback(this._supportsGeolocation); + } else if (window.navigator.permissions !== undefined) { + // navigator.permissions has incomplete browser support + // http://caniuse.com/#feat=permissions-api + // Test for the case where a browser disables Geolocation because of an + // insecure origin + window.navigator.permissions.query({name: 'geolocation'}).then((p) => { + this._supportsGeolocation = p.state !== 'denied'; + callback(this._supportsGeolocation); + }); + } else { + this._supportsGeolocation = !!this.geolocation; + callback(this._supportsGeolocation); + } } /** @@ -389,7 +383,7 @@ class GeolocateControl extends Evented { if (this._geolocationWatchID !== undefined) { this._clearWatch(); } - } else if (error.code === 3 && noTimeout) { + } else if (error.code === 3 && this._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 @@ -551,9 +545,9 @@ class GeolocateControl extends Evented { case 'ACTIVE_LOCK': case 'ACTIVE_ERROR': case 'BACKGROUND_ERROR': - // turn off the GeolocateControl - numberOfWatches--; - noTimeout = false; + // turn off the Geolocate Control + this._numberOfWatches--; + this._noTimeout = false; this._watchState = 'OFF'; this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting'); this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); @@ -611,17 +605,17 @@ class GeolocateControl extends Evented { this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting'); this._geolocateButton.setAttribute('aria-pressed', 'true'); - numberOfWatches++; + this._numberOfWatches++; let positionOptions; - if (numberOfWatches > 1) { + if (this._numberOfWatches > 1) { positionOptions = {maximumAge:600000, timeout:0}; - noTimeout = true; + this._noTimeout = true; } else { positionOptions = this.options.positionOptions; - noTimeout = false; + this._noTimeout = false; } - this._geolocationWatchID = geolocation.watchPosition( + this._geolocationWatchID = this.options.geolocation.watchPosition( this._onSuccess, this._onError, positionOptions); if (this.options.showUserHeading) { @@ -629,7 +623,7 @@ class GeolocateControl extends Evented { } } } else { - geolocation.getCurrentPosition( + this.options.geolocation.getCurrentPosition( this._onSuccess, this._onError, this.options.positionOptions); // This timeout ensures that we still call finish() even if @@ -665,7 +659,7 @@ class GeolocateControl extends Evented { } _clearWatch() { - geolocation.clearWatch(this._geolocationWatchID); + this.options.geolocation.clearWatch(this._geolocationWatchID); window.removeEventListener('deviceorientation', this._onDeviceOrientation); window.removeEventListener('deviceorientationabsolute', this._onDeviceOrientation); From b09275d09314d82f9380d22a4486a5114f921c87 Mon Sep 17 00:00:00 2001 From: Behnam Mohammadi Date: Mon, 21 Dec 2020 16:13:49 +0330 Subject: [PATCH 3/6] fix: removes default value --- src/ui/control/geolocate_control.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 83f2d58cc2b..a7b8c292ade 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -105,9 +105,9 @@ class GeolocateControl extends Evented { _heading: ?number; _updateMarkerRotationThrottled: Function; - _numberOfWatches: number = 0; - _noTimeout: boolean = false; - _supportsGeolocation: boolean = false; + _numberOfWatches: number; + _noTimeout: boolean; + _supportsGeolocation: boolean; constructor(options: Options) { super(); @@ -126,6 +126,7 @@ class GeolocateControl extends Evented { ], this); this._updateMarkerRotationThrottled = throttle(this._updateMarkerRotation, 20); + this._numberOfWatches = 0; } onAdd(map: Map): HTMLElement { From 8876d3f84462f54b2d0137f508d09d7bbc392725 Mon Sep 17 00:00:00 2001 From: Behnam Mohammadi Date: Mon, 21 Dec 2020 16:43:05 +0330 Subject: [PATCH 4/6] style: fix missing type annotation --- src/ui/control/geolocate_control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index a7b8c292ade..53a7e721c40 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -158,7 +158,7 @@ class GeolocateControl extends Evented { this._noTimeout = false; } - _checkGeolocationSupport(callback) { + _checkGeolocationSupport(callback: (supported: boolean) => any) { if (this._supportsGeolocation !== undefined) { callback(this._supportsGeolocation); } else if (window.navigator.permissions !== undefined) { From 47e502859e7bcd6b062b211b775763a5c5f86d39 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Thu, 17 Mar 2022 18:30:01 +0200 Subject: [PATCH 5/6] fix lint and flow --- src/ui/control/geolocate_control.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 53a7e721c40..f7f69c57c4e 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -13,13 +13,13 @@ import type Map from '../map.js'; import type {AnimationOptions, CameraOptions} from '../camera.js'; type Options = { - positionOptions?: PositionOptions, - fitBoundsOptions?: AnimationOptions & CameraOptions, - trackUserLocation?: boolean, - showAccuracyCircle?: boolean, - showUserLocation?: boolean, - showUserHeading?: boolean, - geolocation?: Geolocation, + positionOptions: PositionOptions, + fitBoundsOptions: AnimationOptions & CameraOptions, + trackUserLocation: boolean, + showAccuracyCircle: boolean, + showUserLocation: boolean, + showUserHeading: boolean, + geolocation: Geolocation, }; type DeviceOrientationEvent = { @@ -75,7 +75,7 @@ const defaultOptions: Options = { * @param {Object} [options.showAccuracyCircle=true] By default, if `showUserLocation` is `true`, a transparent circle will be drawn around the user location indicating the accuracy (95% confidence level) of the user's location. Set to `false` to disable. Always disabled when `showUserLocation` is `false`. * @param {Object} [options.showUserLocation=true] By default a dot will be shown on the map at the user's location. Set to `false` to disable. * @param {Object} [options.showUserHeading=false] If `true` an arrow will be drawn next to the user location dot indicating the device's heading. This only has affect when `trackUserLocation` is `true`. - * @param {Object} [options.geolocation=window.navigator.geolocation] By default geolocation uses window.navigator.geolocation but you can customize this object + * @param {Object} [options.geolocation=window.navigator.geolocation] `window.navigator.geolocation` by default; you can provide an object with the same shape to customize geolocation handling. * * @example * map.addControl(new mapboxgl.GeolocateControl({ @@ -109,7 +109,7 @@ class GeolocateControl extends Evented { _noTimeout: boolean; _supportsGeolocation: boolean; - constructor(options: Options) { + constructor(options: $Shape) { super(); this.options = extend({}, defaultOptions, options); From 86e0c785a54dc46dfd261a25c74c9f2946e8e5d2 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Thu, 17 Mar 2022 18:49:06 +0200 Subject: [PATCH 6/6] fixup --- src/ui/control/geolocate_control.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index f7f69c57c4e..a89fc4f0098 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -31,7 +31,7 @@ type DeviceOrientationEvent = { webkitCompassHeading?: number, } -const defaultOptions: Options = { +const defaultOptions = { positionOptions: { enableHighAccuracy: false, maximumAge: 0, @@ -43,8 +43,7 @@ const defaultOptions: Options = { trackUserLocation: false, showAccuracyCircle: true, showUserLocation: true, - showUserHeading: false, - geolocation: window.navigator.geolocation + showUserHeading: false }; /** @@ -111,7 +110,8 @@ class GeolocateControl extends Evented { constructor(options: $Shape) { super(); - this.options = extend({}, defaultOptions, options); + const geolocation = window.navigator.geolocation; + this.options = extend({geolocation}, defaultOptions, options); bindAll([ '_onSuccess',