Spaces:
Sleeping
Sleeping
| // @flow | |
| import LngLat from '../geo/lng_lat'; | |
| import type Point from '@mapbox/point-geometry'; | |
| import type Transform from '../geo/transform'; | |
| /** | |
| * Given a LngLat, prior projected position, and a transform, return a new LngLat shifted | |
| * n × 360° east or west for some n ≥ 0 such that: | |
| * | |
| * * the projected location of the result is on screen, if possible, and secondarily: | |
| * * the difference between the projected location of the result and the prior position | |
| * is minimized. | |
| * | |
| * The object is to preserve perceived object constancy for Popups and Markers as much as | |
| * possible; they should avoid shifting large distances across the screen, even when the | |
| * map center changes by ±360° due to automatic wrapping, and when about to go off screen, | |
| * should wrap just enough to avoid doing so. | |
| * | |
| * @private | |
| */ | |
| export default function(lngLat: LngLat, priorPos: ?Point, transform: Transform): LngLat { | |
| lngLat = new LngLat(lngLat.lng, lngLat.lat); | |
| // First, try shifting one world in either direction, and see if either is closer to the | |
| // prior position. This preserves object constancy when the map center is auto-wrapped | |
| // during animations. | |
| if (priorPos) { | |
| const left = new LngLat(lngLat.lng - 360, lngLat.lat); | |
| const right = new LngLat(lngLat.lng + 360, lngLat.lat); | |
| const delta = transform.locationPoint(lngLat).distSqr(priorPos); | |
| if (transform.locationPoint(left).distSqr(priorPos) < delta) { | |
| lngLat = left; | |
| } else if (transform.locationPoint(right).distSqr(priorPos) < delta) { | |
| lngLat = right; | |
| } | |
| } | |
| // Second, wrap toward the center until the new position is on screen, or we can't get | |
| // any closer. | |
| while (Math.abs(lngLat.lng - transform.center.lng) > 180) { | |
| const pos = transform.locationPoint(lngLat); | |
| if (pos.x >= 0 && pos.y >= 0 && pos.x <= transform.width && pos.y <= transform.height) { | |
| break; | |
| } | |
| if (lngLat.lng > transform.center.lng) { | |
| lngLat.lng -= 360; | |
| } else { | |
| lngLat.lng += 360; | |
| } | |
| } | |
| return lngLat; | |
| } | |