Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

take Geolocation accuracy into account with the Geolocate control #3737

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions debug/debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
positionOptions: {
enableHighAccuracy: true
},
fitBoundsOptions: {
maxZoom: 20
},
watchPosition: true
}));
map.addControl(new mapboxgl.ScaleControl());
Expand Down
18 changes: 18 additions & 0 deletions js/geo/lng_lat.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ class LngLat {
toString() {
return `LngLat(${this.lng}, ${this.lat})`;
}

/**
* Returns a `LngLatBounds` from the coordinates extended by a given `radius`.
*
* @param {number} radius Distance in meters from the coordinates to extend the bounds.
* @returns {LngLatBounds} A new `LngLatBounds` object representing the coordinates extended by the `radius`.
* @example
* var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
* ll.toBounds(100).toArray(); // = [[-73.97501862141328, 40.77351016847229], [-73.97478137858673, 40.77368983152771]]
*/
toBounds(radius) {
const latAccuracy = 360 * radius / 40075017,
lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);

const LngLatBounds = require('./lng_lat_bounds');
return new LngLatBounds(new LngLat(this.lng - lngAccuracy, this.lat - latAccuracy),
new LngLat(this.lng + lngAccuracy, this.lat + latAccuracy));
}
}

/**
Expand Down
18 changes: 11 additions & 7 deletions js/ui/control/geolocate_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Evented = require('../../util/evented');
const DOM = require('../../util/dom');
const window = require('../../util/window');
const util = require('../../util/util');
const LngLat = require('../../geo/lng_lat');

const defaultGeoPositionOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ };
const className = 'mapboxgl-ctrl';
Expand Down Expand Up @@ -40,9 +41,12 @@ function checkGeolocationSupport(callback) {
* geolocation support is not available, the GeolocateControl will not
* be visible.
*
* The zoom level applied will depend on the accuracy of the geolocation provided by the device.
*
* @implements {IControl}
* @param {Object} [options]
* @param {Object} [options.positionOptions={enableHighAccuracy: false, timeout: 6000}] A [PositionOptions](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) object.
* @param {Object} [options.positionOptions={enableHighAccuracy: false, timeout: 6000}] A Geolocation API [PositionOptions](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) object.
* @param {Object} [options.fitBoundsOptions={maxZoom: 18}] A [`fitBounds`](#Map#fitBounds) options object to use when the map is panned and zoomed to the device location. The default is to use a `maxZoom` of 18 to limit how far the map will zoom in for very accurate locations.
* @param {Object} [options.watchPosition=false] If `true` the map will reposition each time the position of the device changes and the control becomes a toggle.
* @example
* map.addControl(new mapboxgl.GeolocateControl({
Expand Down Expand Up @@ -77,12 +81,12 @@ class GeolocateControl extends Evented {
}

_onSuccess(position) {
this._map.jumpTo({
center: [position.coords.longitude, position.coords.latitude],
zoom: 17,
bearing: 0,
pitch: 0
});
const center = new LngLat(position.coords.longitude, position.coords.latitude);
const radius = position.coords.accuracy;

this._map.fitBounds(center.toBounds(radius), util.extend({
maxZoom: (this.options.maxZoom !== undefined) ? this.options.maxZoom : 18
}, this.options.fitBoundsOptions || {}));

this.fire('geolocate', position);
this._finish();
Expand Down
6 changes: 6 additions & 0 deletions test/js/geo/lng_lat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,11 @@ test('LngLat', (t) => {
t.end();
});

t.test('#toBounds', (t) => {
t.deepEqual(new LngLat(0, 0).toBounds(10).toArray(), [[-0.00008983152770714982, -0.00008983152770714982], [0.00008983152770714982, 0.00008983152770714982]]);
t.deepEqual(new LngLat(-73.9749, 40.7736).toBounds(10).toArray(), [[-73.97501862141328, 40.77351016847229], [-73.97478137858673, 40.77368983152771]]);
t.end();
});

t.end();
});