Skip to content

Commit

Permalink
improve GeolocateControl accuracy circle radius computation when movi…
Browse files Browse the repository at this point in the history
…ng map

Using the center position to calculate the pixel scale, and updating calculations at each move/rotate/zoom of the map, as those change the position of the accuracy circle.
  • Loading branch information
tricaric authored Jan 31, 2025
1 parent 4db36c3 commit 6fb1933
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions src/ui/control/geolocate_control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ export class GeolocateControl extends Evented implements IControl {
}

DOM.remove(this._container);
this._map.off('move', this._onMove);
this._map.off('rotate', this._onRotate);

Check warning on line 307 in src/ui/control/geolocate_control.ts

View check run for this annotation

Codecov / codecov/patch

src/ui/control/geolocate_control.ts#L306-L307

Added lines #L306 - L307 were not covered by tests
this._map.off('zoom', this._onZoom);
this._map = undefined;
numberOfWatches = 0;
Expand Down Expand Up @@ -376,6 +378,11 @@ export class GeolocateControl extends Evented implements IControl {
return;
}

if (this.options.showAccuracyCircle) {
// this is needed by _updateCircleRadius()
this._lastKnownPosition = position;
}

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
Expand Down Expand Up @@ -460,16 +467,30 @@ export class GeolocateControl extends Evented implements IControl {
};

_updateCircleRadius() {
const bounds = this._map.getBounds();
const southEastPoint = bounds.getSouthEast();
const northEastPoint = bounds.getNorthEast();
const mapHeightInMeters = southEastPoint.distanceTo(northEastPoint);
const mapHeightInPixels = this._map._container.clientHeight;
const circleDiameter = Math.ceil(2 * (this._accuracy / (mapHeightInMeters / mapHeightInPixels)));
if (!this._lastKnownPosition) return;
const center = new LngLat(this._lastKnownPosition.coords.longitude, this._lastKnownPosition.coords.latitude);
const point = this._map.project(center);
const delta_x_pixels = 10; // arbitrary small offset, in x direction because there is no map tilting in the x direction
const delta = this._map.unproject([point.x + delta_x_pixels, point.y]);
const distance = delta.distanceTo(center);
const pixelScale = distance / delta_x_pixels;
const circleDiameter = 2 * (this._accuracy / pixelScale);

Check warning on line 477 in src/ui/control/geolocate_control.ts

View check run for this annotation

Codecov / codecov/patch

src/ui/control/geolocate_control.ts#L470-L477

Added lines #L470 - L477 were not covered by tests
this._circleElement.style.width = `${circleDiameter}px`;
this._circleElement.style.height = `${circleDiameter}px`;
}

_onMove = () => {
if (this.options.showUserLocation && this.options.showAccuracyCircle) {
this._updateCircleRadius();
}
};

_onRotate = () => {
if (this.options.showUserLocation && this.options.showAccuracyCircle) {
this._updateCircleRadius();
}
};

_onZoom = () => {
if (this.options.showUserLocation && this.options.showAccuracyCircle) {
this._updateCircleRadius();
Expand Down Expand Up @@ -573,6 +594,8 @@ export class GeolocateControl extends Evented implements IControl {

if (this.options.trackUserLocation) this._watchState = 'OFF';

this._map.on('move', this._onMove);
this._map.on('rotate', this._onRotate);
this._map.on('zoom', this._onZoom);
}

Expand Down

0 comments on commit 6fb1933

Please sign in to comment.