Skip to content

Commit 2d7b9b0

Browse files
stepankuzmingithub-actions[bot]
authored andcommitted
[GLJS-1594] Add showButton option to GeolocateControl (internal-8933)
GitOrigin-RevId: b9468dc17e75c3dba8662b6b84f16b9d118722b8
1 parent c63f88c commit 2d7b9b0

File tree

5 files changed

+205
-106
lines changed

5 files changed

+205
-106
lines changed

package-lock.json

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
"lodash": "^4.17.21",
9090
"mapbox-gl-styles": "^2.0.2",
9191
"minimist": "^1.2.6",
92-
"mock-geolocation": "^1.0.11",
9392
"node-notifier": "^10.0.1",
9493
"npm-font-open-sans": "^1.1.0",
9594
"npm-run-all2": "^8.0.4",

src/ui/control/geolocate_control.ts

Lines changed: 39 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@ export type GeolocateControlOptions = {
1919
showUserLocation?: boolean;
2020
showUserHeading?: boolean;
2121
geolocation?: Geolocation;
22+
showButton?: boolean;
2223
};
2324

24-
type DeviceOrientationEvent = {
25-
absolute: boolean;
26-
alpha: number;
27-
beta: number;
28-
gamma: number;
29-
requestPermission: Promise<string>;
30-
webkitCompassHeading?: number;
25+
declare global {
26+
interface DeviceOrientationEvent {
27+
readonly webkitCompassHeading?: number;
28+
}
29+
}
30+
31+
type DeviceOrientationEventStatic = typeof DeviceOrientationEvent & {
32+
requestPermission?: () => Promise<'granted' | 'denied' | 'prompt'>;
3133
};
3234

35+
type WatchState = 'OFF' | 'ACTIVE_LOCK' | 'WAITING_ACTIVE' | 'ACTIVE_ERROR' | 'BACKGROUND' | 'BACKGROUND_ERROR';
36+
3337
const defaultOptions = {
3438
positionOptions: {
3539
enableHighAccuracy: false,
@@ -42,7 +46,8 @@ const defaultOptions = {
4246
trackUserLocation: false,
4347
showAccuracyCircle: true,
4448
showUserLocation: true,
45-
showUserHeading: false
49+
showUserHeading: false,
50+
showButton: true
4651
};
4752

4853
type GeolocateControlEvents = {
@@ -82,6 +87,7 @@ type GeolocateControlEvents = {
8287
* @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.
8388
* @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`.
8489
* @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.
90+
* @param {boolean} [options.showButton=true] If `false`, the control button will be hidden. The user location dot can still be shown by setting `showUserLocation` to `true` and calling {@link GeolocateControl#trigger} programmatically.
8591
*
8692
* @example
8793
* map.addControl(new mapboxgl.GeolocateControl({
@@ -91,6 +97,16 @@ type GeolocateControlEvents = {
9197
* trackUserLocation: true,
9298
* showUserHeading: true
9399
* }));
100+
*
101+
* @example
102+
* // Tracking without visible button - call trigger() to start
103+
* const geolocate = new mapboxgl.GeolocateControl({
104+
* trackUserLocation: true,
105+
* showUserLocation: true,
106+
* showButton: false
107+
* });
108+
* map.addControl(geolocate);
109+
* geolocate.trigger();
94110
* @see [Example: Locate the user](https://www.mapbox.com/mapbox-gl-js/example/locate-user/)
95111
*/
96112
class GeolocateControl extends Evented<GeolocateControlEvents> implements IControl {
@@ -102,7 +118,7 @@ class GeolocateControl extends Evented<GeolocateControlEvents> implements IContr
102118
_geolocateButton: HTMLButtonElement;
103119
_geolocationWatchID: number;
104120
_timeoutId?: number;
105-
_watchState: 'OFF' | 'ACTIVE_LOCK' | 'WAITING_ACTIVE' | 'ACTIVE_ERROR' | 'BACKGROUND' | 'BACKGROUND_ERROR';
121+
_watchState: WatchState;
106122
_lastKnownPosition?: GeolocationPosition;
107123
_userLocationDotMarker: Marker;
108124
_accuracyCircleMarker: Marker;
@@ -475,6 +491,10 @@ class GeolocateControl extends Evented<GeolocateControlEvents> implements IContr
475491

476492
this._setup = true;
477493

494+
if (!this.options.showButton) {
495+
this._container.style.display = 'none';
496+
}
497+
478498
// when the camera is changed (and it's not as a result of the Geolocation Control) change
479499
// the watch mode to background watch, so that the marker is updated but not the camera.
480500
if (this.options.trackUserLocation) {
@@ -588,24 +608,22 @@ class GeolocateControl extends Evented<GeolocateControlEvents> implements IContr
588608
}
589609

590610
// incoming state setup
591-
switch (this._watchState) {
611+
// assert WatchState type to prevent TypeScript from narrowing after first switch
612+
switch (this._watchState as WatchState) {
592613
case 'WAITING_ACTIVE':
593614
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
594615
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active');
595616
break;
596617
case 'ACTIVE_LOCK':
597618
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active');
598619
break;
599-
// @ts-expect-error - TS2678 - Type '"ACTIVE_ERROR"' is not comparable to type '"OFF" | "ACTIVE_LOCK" | "WAITING_ACTIVE"'.
600620
case 'ACTIVE_ERROR':
601621
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
602622
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error');
603623
break;
604-
// @ts-expect-error - TS2678 - Type '"BACKGROUND"' is not comparable to type '"OFF" | "ACTIVE_LOCK" | "WAITING_ACTIVE"'.
605624
case 'BACKGROUND':
606625
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background');
607626
break;
608-
// @ts-expect-error - TS2678 - Type '"BACKGROUND_ERROR"' is not comparable to type '"OFF" | "ACTIVE_LOCK" | "WAITING_ACTIVE"'.
609627
case 'BACKGROUND_ERROR':
610628
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
611629
this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background-error');
@@ -656,28 +674,18 @@ class GeolocateControl extends Evented<GeolocateControlEvents> implements IContr
656674

657675
_addDeviceOrientationListener() {
658676
const addListener = () => {
659-
if ('ondeviceorientationabsolute' in window) {
660-
// @ts-expect-error - TS2769 - No overload matches this call.
661-
window.addEventListener('deviceorientationabsolute', this._onDeviceOrientation);
662-
} else {
663-
// @ts-expect-error - TS2769 - No overload matches this call.
664-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
665-
window.addEventListener('deviceorientation', this._onDeviceOrientation);
666-
}
677+
const eventName = 'ondeviceorientationabsolute' in window ?
678+
'deviceorientationabsolute' :
679+
'deviceorientation';
680+
681+
window.addEventListener(eventName, this._onDeviceOrientation);
667682
};
668683

669-
// @ts-expect-error - TS2339 - Property 'requestPermission' does not exist on type '{ new (type: string, eventInitDict?: DeviceMotionEventInit): DeviceMotionEvent; prototype: DeviceMotionEvent; }'.
670-
if (typeof DeviceMotionEvent !== "undefined" && typeof DeviceMotionEvent.requestPermission === 'function') {
671-
// @ts-expect-error - TS2339 - Property 'requestPermission' does not exist on type '{ new (type: string, eventInitDict?: DeviceOrientationEventInit): DeviceOrientationEvent; prototype: DeviceOrientationEvent; }'.
672-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
673-
DeviceOrientationEvent.requestPermission()
674-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
684+
if (typeof (DeviceOrientationEvent as DeviceOrientationEventStatic).requestPermission === 'function') {
685+
(DeviceOrientationEvent as DeviceOrientationEventStatic).requestPermission()
675686
.then(response => {
676-
if (response === 'granted') {
677-
addListener();
678-
}
687+
if (response === 'granted') addListener();
679688
})
680-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
681689
.catch(console.error);
682690
} else {
683691
addListener();
@@ -687,9 +695,7 @@ class GeolocateControl extends Evented<GeolocateControlEvents> implements IContr
687695
_clearWatch() {
688696
this.options.geolocation.clearWatch(this._geolocationWatchID);
689697

690-
// @ts-expect-error - TS2769 - No overload matches this call.
691698
window.removeEventListener('deviceorientation', this._onDeviceOrientation);
692-
// @ts-expect-error - TS2769 - No overload matches this call.
693699
window.removeEventListener('deviceorientationabsolute', this._onDeviceOrientation);
694700

695701
this._geolocationWatchID = undefined;

0 commit comments

Comments
 (0)