diff --git a/src/ui/marker.ts b/src/ui/marker.ts index 9610f80449c..150f7a8ea21 100644 --- a/src/ui/marker.ts +++ b/src/ui/marker.ts @@ -94,6 +94,7 @@ export default class Marker extends Evented { _updateFrameId: number; _updateMoving: () => void; _occludedOpacity: number; + _lngLatDirty: boolean; constructor(options?: MarkerOptions, legacyOptions?: MarkerOptions) { super(); @@ -125,6 +126,7 @@ export default class Marker extends Evented { this._pitchAlignment = (options && options.pitchAlignment && options.pitchAlignment) || 'auto'; this._updateMoving = () => this._update(true); this._occludedOpacity = (options && options.occludedOpacity) || 0.2; + this._lngLatDirty = false; if (!options || !options.element) { this._defaultMarker = true; @@ -294,7 +296,9 @@ export default class Marker extends Evented { * @see [Example: Add a marker using a place name](https://docs.mapbox.com/mapbox-gl-js/example/marker-from-geocode/) */ setLngLat(lnglat: LngLatLike): this { - this._lngLat = LngLat.convert(lnglat); + const newLngLat = LngLat.convert(lnglat); + this._lngLatDirty = this._lngLat == null || this._lngLat.lat !== newLngLat.lat || this._lngLat.lng !== newLngLat.lng; + this._lngLat = newLngLat; this._pos = null; if (this._popup) this._popup.setLngLat(this._lngLat); this._update(true); @@ -575,8 +579,9 @@ export default class Marker extends Evented { // because rounding the coordinates at every `move` event causes stuttered zooming // we only round them when _update is called with `moveend` or when its called with - // no arguments (when the Marker is initialized or Marker#setLngLat is invoked). - if (delaySnap === true) { + // no arguments (when the Marker is initialized or Marker#setLngLat is invoked) or + // when the coordinates have not changed. + if (delaySnap === true && this._lngLatDirty) { this._updateFrameId = requestAnimationFrame(() => { if (this._element && this._pos && this._anchor) { this._pos = this._pos.round(); @@ -586,6 +591,7 @@ export default class Marker extends Evented { } else { this._pos = this._pos.round(); } + this._lngLatDirty = false; map._requestDomTask(() => { if (!this._map) return; diff --git a/test/unit/ui/marker.test.ts b/test/unit/ui/marker.test.ts index e66bd996771..459a4806e1a 100644 --- a/test/unit/ui/marker.test.ts +++ b/test/unit/ui/marker.test.ts @@ -1550,6 +1550,16 @@ describe('Snap To Pixel', () => { }, 100); }); }); + test("Immediately Snap To Pixel After setLngLat if unchanged", async () => { + marker.setLngLat(marker.getLngLat()); + const pos = marker._pos; + await new Promise(resolve => { + setTimeout(() => { + expect(marker._pos).toStrictEqual(pos.round()); + resolve(); + }, 100); + }); + }); test("Immediately Snap To Pixel on moveend", () => { map.fire(new Event("moveend")); expect(marker._pos).toStrictEqual(marker._pos.round());