From 7ec6a5d354dc3e75cd73474d9be0c99baaeffe08 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sat, 14 Sep 2019 23:44:37 +0430 Subject: [PATCH 1/8] Check maxBounds in geolocate control --- src/ui/control/geolocate_control.js | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index e6df08589c2..4118f11d471 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -137,7 +137,30 @@ class GeolocateControl extends Evented { this._map = (undefined: any); } + _isOutOfMapMaxBounds(position: Position) { + const bounds = this._map.getMaxBounds(); + const coordinates = position.coords; + + return bounds && ( + coordinates.longitude < bounds.getWest() || + coordinates.longitude > bounds.getEast() || + coordinates.latitude < bounds.getSouth() || + coordinates.latitude > bounds.getNorth() + ) + } + _onSuccess(position: Position) { + if (this._isOutOfMapMaxBounds(position)) { + this._watchState = 'ACTIVE_ERROR'; + this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); + this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); + + this.fire(new Event('outofmaxbounds', position)); + this._finish(); + + return; + } + if (this.options.trackUserLocation) { // keep a record of the position so that if the state is BACKGROUND and the user // clicks the button, we can move to ACTIVE_LOCK immediately without waiting for @@ -456,6 +479,16 @@ export default GeolocateControl; * */ +/** + * Fired on each Geolocation API position update which returned as success but user position is out of map maxBounds. + * + * @event outofmaxbounds + * @memberof GeolocateControl + * @instance + * @property {Position} data The returned [Position](https://developer.mozilla.org/en-US/docs/Web/API/Position) object from the callback in [Geolocation.getCurrentPosition()](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition) or [Geolocation.watchPosition()](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition). + * + */ + /** * Fired when the Geolocate Control changes to the active lock state, which happens either upon first obtaining a successful Geolocation API position for the user (a geolocate event will follow), or the user clicks the geolocate button when in the background state which uses the last known position to recenter the map and enter active lock state (no geolocate event will follow unless the users's location changes). * From 23047904e79babc71ed966b3513d63f6ee2629a5 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sat, 14 Sep 2019 23:49:43 +0430 Subject: [PATCH 2/8] Add test for geolocate control outofmaxbounds event --- test/unit/ui/control/geolocate.test.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/unit/ui/control/geolocate.test.js b/test/unit/ui/control/geolocate.test.js index beda845f55e..4116503b31d 100644 --- a/test/unit/ui/control/geolocate.test.js +++ b/test/unit/ui/control/geolocate.test.js @@ -48,6 +48,27 @@ test('GeolocateControl error event', (t) => { geolocation.sendError({code: 2, message: 'error message'}); }); +test('GeolocateControl outofmaxbounds event', (t) => { + t.plan(4); + + const map = createMap(t); + const geolocate = new GeolocateControl(); + map.addControl(geolocate); + map.setMaxBounds([[0, 0], [10, 10]]); + + const click = new window.Event('click'); + + geolocate.on('outofmaxbounds', (position) => { + t.equal(position.coords.latitude, 10, 'geolocate position latitude'); + t.equal(position.coords.longitude, 20, 'geolocate position longitude'); + t.equal(position.coords.accuracy, 3, 'geolocate position accuracy'); + t.equal(position.timestamp, 4, 'geolocate timestamp'); + t.end(); + }); + geolocate._geolocateButton.dispatchEvent(click); + geolocation.send({latitude: 10, longitude: 20, accuracy: 3, timestamp: 4}); +}); + test('GeolocateControl geolocate event', (t) => { t.plan(4); From ebb78f5dd78647fd467782a21bfeafd890d919af Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sat, 14 Sep 2019 23:54:23 +0430 Subject: [PATCH 3/8] Remove marker in geolocate control on outofmaxbounds event --- src/ui/control/geolocate_control.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 4118f11d471..71b9bd086ec 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -156,6 +156,7 @@ class GeolocateControl extends Evented { this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); this.fire(new Event('outofmaxbounds', position)); + this._updateMarker() this._finish(); return; From ddcac67734adbf97866f75770fdfcf11c690f350 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sun, 15 Sep 2019 11:20:16 +0430 Subject: [PATCH 4/8] Fix eslint errors --- src/ui/control/geolocate_control.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 71b9bd086ec..cad230c679a 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -146,7 +146,7 @@ class GeolocateControl extends Evented { coordinates.longitude > bounds.getEast() || coordinates.latitude < bounds.getSouth() || coordinates.latitude > bounds.getNorth() - ) + ); } _onSuccess(position: Position) { @@ -156,9 +156,9 @@ class GeolocateControl extends Evented { this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); this.fire(new Event('outofmaxbounds', position)); - this._updateMarker() + this._updateMarker(); this._finish(); - + return; } From 743898aea4e40bd1478200ba27272fe0facd2590 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sun, 15 Sep 2019 23:16:07 +0430 Subject: [PATCH 5/8] Set geolocate control state on outofmaxbounds event based on current watch state --- src/ui/control/geolocate_control.js | 56 +++++++++++++++-------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index cad230c679a..6679fab2f1a 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -149,11 +149,37 @@ class GeolocateControl extends Evented { ); } - _onSuccess(position: Position) { - if (this._isOutOfMapMaxBounds(position)) { + _goToErrorState() { + switch (this._watchState) { + case 'WAITING_ACTIVE': this._watchState = 'ACTIVE_ERROR'; this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); + break; + case 'ACTIVE_LOCK': + this._watchState = 'ACTIVE_ERROR'; + this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); + this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); + this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting'); + // turn marker grey + break; + case 'BACKGROUND': + this._watchState = 'BACKGROUND_ERROR'; + this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background'); + this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background-error'); + this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting'); + // turn marker grey + break; + case 'ACTIVE_ERROR': + break; + default: + assert(false, `Unexpected watchState ${this._watchState}`); + } + } + + _onSuccess(position: Position) { + if (this._isOutOfMapMaxBounds(position)) { + this._goToErrorState(); this.fire(new Event('outofmaxbounds', position)); this._updateMarker(); @@ -242,31 +268,7 @@ class GeolocateControl extends Evented { this._clearWatch(); } } else { - switch (this._watchState) { - case 'WAITING_ACTIVE': - this._watchState = 'ACTIVE_ERROR'; - this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); - this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); - break; - case 'ACTIVE_LOCK': - this._watchState = 'ACTIVE_ERROR'; - this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active'); - this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error'); - this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting'); - // turn marker grey - break; - case 'BACKGROUND': - this._watchState = 'BACKGROUND_ERROR'; - this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background'); - this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background-error'); - this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting'); - // turn marker grey - break; - case 'ACTIVE_ERROR': - break; - default: - assert(false, `Unexpected watchState ${this._watchState}`); - } + this._goToErrorState(); } } From 154f8e66fa78c815f0cc9eda37cd6b9358989ca4 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Sun, 15 Sep 2019 23:37:50 +0430 Subject: [PATCH 6/8] Add test for geolocate control watch state --- test/unit/ui/control/geolocate.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/ui/control/geolocate.test.js b/test/unit/ui/control/geolocate.test.js index 4116503b31d..8b4cafbb54e 100644 --- a/test/unit/ui/control/geolocate.test.js +++ b/test/unit/ui/control/geolocate.test.js @@ -49,16 +49,18 @@ test('GeolocateControl error event', (t) => { }); test('GeolocateControl outofmaxbounds event', (t) => { - t.plan(4); + t.plan(5); const map = createMap(t); const geolocate = new GeolocateControl(); map.addControl(geolocate); map.setMaxBounds([[0, 0], [10, 10]]); + geolocate._watchState = 'ACTIVE_LOCK'; const click = new window.Event('click'); geolocate.on('outofmaxbounds', (position) => { + t.equal(geolocate._watchState, 'ACTIVE_ERROR', 'geolocate state'); t.equal(position.coords.latitude, 10, 'geolocate position latitude'); t.equal(position.coords.longitude, 20, 'geolocate position longitude'); t.equal(position.coords.accuracy, 3, 'geolocate position accuracy'); From 3c13d2a83558151a32fe09512422858f44df37c3 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Mon, 16 Sep 2019 10:56:16 +0430 Subject: [PATCH 7/8] Rename _setErrorState method in geolocate control --- src/ui/control/geolocate_control.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/control/geolocate_control.js b/src/ui/control/geolocate_control.js index 6679fab2f1a..eca7accc8df 100644 --- a/src/ui/control/geolocate_control.js +++ b/src/ui/control/geolocate_control.js @@ -149,7 +149,7 @@ class GeolocateControl extends Evented { ); } - _goToErrorState() { + _setErrorState() { switch (this._watchState) { case 'WAITING_ACTIVE': this._watchState = 'ACTIVE_ERROR'; @@ -179,7 +179,7 @@ class GeolocateControl extends Evented { _onSuccess(position: Position) { if (this._isOutOfMapMaxBounds(position)) { - this._goToErrorState(); + this._setErrorState(); this.fire(new Event('outofmaxbounds', position)); this._updateMarker(); @@ -268,7 +268,7 @@ class GeolocateControl extends Evented { this._clearWatch(); } } else { - this._goToErrorState(); + this._setErrorState(); } } From 97b67c5081e78a4cbdc87ff38c6039f305ae5f65 Mon Sep 17 00:00:00 2001 From: Hossein Moradi Davijani Date: Mon, 16 Sep 2019 10:59:57 +0430 Subject: [PATCH 8/8] Add test case in geolocate control for the background outofmaxbounds error state --- test/unit/ui/control/geolocate.test.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/test/unit/ui/control/geolocate.test.js b/test/unit/ui/control/geolocate.test.js index 8b4cafbb54e..523e96076e7 100644 --- a/test/unit/ui/control/geolocate.test.js +++ b/test/unit/ui/control/geolocate.test.js @@ -48,7 +48,7 @@ test('GeolocateControl error event', (t) => { geolocation.sendError({code: 2, message: 'error message'}); }); -test('GeolocateControl outofmaxbounds event', (t) => { +test('GeolocateControl outofmaxbounds event in active lock state', (t) => { t.plan(5); const map = createMap(t); @@ -71,6 +71,29 @@ test('GeolocateControl outofmaxbounds event', (t) => { geolocation.send({latitude: 10, longitude: 20, accuracy: 3, timestamp: 4}); }); +test('GeolocateControl outofmaxbounds event in background state', (t) => { + t.plan(5); + + const map = createMap(t); + const geolocate = new GeolocateControl(); + map.addControl(geolocate); + map.setMaxBounds([[0, 0], [10, 10]]); + geolocate._watchState = 'BACKGROUND'; + + const click = new window.Event('click'); + + geolocate.on('outofmaxbounds', (position) => { + t.equal(geolocate._watchState, 'BACKGROUND_ERROR', 'geolocate state'); + t.equal(position.coords.latitude, 10, 'geolocate position latitude'); + t.equal(position.coords.longitude, 20, 'geolocate position longitude'); + t.equal(position.coords.accuracy, 3, 'geolocate position accuracy'); + t.equal(position.timestamp, 4, 'geolocate timestamp'); + t.end(); + }); + geolocate._geolocateButton.dispatchEvent(click); + geolocation.send({latitude: 10, longitude: 20, accuracy: 3, timestamp: 4}); +}); + test('GeolocateControl geolocate event', (t) => { t.plan(4);