Fix globe/mercator projection transition (#2229)

This commit is contained in:
Xiaoji Chen 2023-07-13 19:12:16 -07:00 committed by Xiaoji Chen
parent 2ced11ad0b
commit 575f2443a7
3 changed files with 39 additions and 4 deletions

View File

@ -1,4 +1,9 @@
import {transformToViewState, applyViewStateToTransform, cloneTransform} from '../utils/transform';
import {
transformToViewState,
applyViewStateToTransform,
cloneTransform,
syncProjection
} from '../utils/transform';
import {normalizeStyle} from '../utils/style-utils';
import {deepEqual} from '../utils/deep-equal';
@ -394,7 +399,11 @@ export default class Mapbox<MapT extends MapInstance = MapInstance> {
map.on('resize', () => {
this._renderTransform.resize(map.transform.width, map.transform.height);
});
map.on('styledata', () => this._updateStyleComponents(this.props, {}));
map.on('styledata', () => {
this._updateStyleComponents(this.props, {});
// Projection can be set in stylesheet
syncProjection(map.transform, this._renderTransform);
});
map.on('sourcedata', () => this._updateStyleComponents(this.props, {}));
for (const eventName in pointerEvents) {
map.on(eventName, this._onPointerEvent);
@ -728,11 +737,14 @@ export default class Mapbox<MapT extends MapInstance = MapInstance> {
const tr = this._map.transform;
// Make sure camera matches the current props
this._map.transform = this._renderTransform;
map.transform = this._renderTransform;
this._onAfterRepaint = () => {
// Mapbox transitions between non-mercator projection and mercator during render time
// Copy it back to the other
syncProjection(this._renderTransform, tr);
// Restores camera state before render/load events are fired
this._map.transform = tr;
map.transform = tr;
};
}

View File

@ -1,4 +1,5 @@
import type {PaddingOptions, LngLat, Point, LngLatLike, PointLike} from './common';
import type {Projection} from './style-spec';
export interface IControl<MapT extends MapInstance = MapInstance> {
onAdd(map: MapT): HTMLElement;
@ -217,6 +218,10 @@ export type Transform = {
getBounds: () => any;
locationPoint: (lngLat: LngLat) => Point;
pointLocation: (p: Point) => LngLat;
// Mapbox only
getProjection?: () => Projection;
setProjection?: (projection: Projection) => void;
};
export type MapInstanceInternal<MapT extends MapInstance> = MapT & {

View File

@ -1,5 +1,6 @@
import type {MapboxProps} from '../mapbox/mapbox';
import type {Transform, ViewState} from '../types';
import {deepEqual} from './deep-equal';
/**
* Make a copy of a transform
@ -12,6 +13,23 @@ export function cloneTransform(tr: Transform): Transform {
return newTransform;
}
/**
* Copy projection from one transform to another. This only applies to mapbox-gl transforms
* @param src the transform to copy projection settings from
* @param dest to transform to copy projection settings to
*/
export function syncProjection(src: Transform, dest: Transform): void {
if (!src.getProjection) {
return;
}
const srcProjection = src.getProjection();
const destProjection = dest.getProjection();
if (!deepEqual(srcProjection, destProjection)) {
dest.setProjection(srcProjection);
}
}
/**
* Capture a transform's current state
* @param transform