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

feat: send geolocation as adapter #10400

Closed
Closed
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
85 changes: 43 additions & 42 deletions src/ui/control/geolocate_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type Options = {
trackUserLocation?: boolean,
showAccuracyCircle?: boolean,
showUserLocation?: boolean,
showUserHeading?: boolean
showUserHeading?: boolean,
geolocation?: Geolocation,
};

type DeviceOrientationEvent = {
Expand All @@ -42,34 +43,10 @@ const defaultOptions: Options = {
trackUserLocation: false,
showAccuracyCircle: true,
showUserLocation: true,
showUserHeading: false
showUserHeading: false,
geolocation: window.navigator.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 = !!window.navigator.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.
Expand Down Expand Up @@ -98,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({
Expand Down Expand Up @@ -128,6 +106,10 @@ class GeolocateControl extends Evented {
_updateMarkerRotationThrottled: Function;
_onDeviceOrientationListener: Function;

_numberOfWatches: number;
_noTimeout: boolean;
_supportsGeolocation: boolean;

constructor(options: Options) {
super();
this.options = extend({}, defaultOptions, options);
Expand All @@ -146,19 +128,20 @@ class GeolocateControl extends Evented {
// by referencing the function with .bind(), we can correctly remove from window's event listeners
this._onDeviceOrientationListener = this._onDeviceOrientation.bind(this);
this._updateMarkerRotationThrottled = throttle(this._updateMarkerRotation, 20);
this._numberOfWatches = 0;
}

onAdd(map: Map) {
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) {
window.navigator.geolocation.clearWatch(this._geolocationWatchID);
this.options.geolocation.clearWatch(this._geolocationWatchID);
this._geolocationWatchID = (undefined: any);
}

Expand All @@ -173,8 +156,26 @@ class GeolocateControl extends Evented {
DOM.remove(this._container);
this._map.off('zoom', this._onZoom);
this._map = (undefined: any);
numberOfWatches = 0;
noTimeout = false;
this._numberOfWatches = 0;
this._noTimeout = false;
}

_checkGeolocationSupport(callback: (supported: boolean) => any) {
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);
}
}

/**
Expand Down Expand Up @@ -385,7 +386,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
Expand Down Expand Up @@ -547,9 +548,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');
Expand Down Expand Up @@ -607,25 +608,25 @@ 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 = window.navigator.geolocation.watchPosition(
this._geolocationWatchID = this.options.geolocation.watchPosition(
this._onSuccess, this._onError, positionOptions);

if (this.options.showUserHeading) {
this._addDeviceOrientationListener();
}
}
} else {
window.navigator.geolocation.getCurrentPosition(
this.options.geolocation.getCurrentPosition(
this._onSuccess, this._onError, this.options.positionOptions);

// This timeout ensures that we still call finish() even if
Expand Down Expand Up @@ -661,7 +662,7 @@ class GeolocateControl extends Evented {
}

_clearWatch() {
window.navigator.geolocation.clearWatch(this._geolocationWatchID);
this.options.geolocation.clearWatch(this._geolocationWatchID);

window.removeEventListener('deviceorientation', this._onDeviceOrientationListener);
window.removeEventListener('deviceorientationabsolute', this._onDeviceOrientationListener);
Expand Down