diff --git a/src/mapbox/mapbox.ts b/src/mapbox/mapbox.ts index 7f7e34636..7396635ac 100644 --- a/src/mapbox/mapbox.ts +++ b/src/mapbox/mapbox.ts @@ -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 { 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 { 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; }; } diff --git a/src/types/lib.ts b/src/types/lib.ts index 244591374..fdebe25d1 100644 --- a/src/types/lib.ts +++ b/src/types/lib.ts @@ -1,4 +1,5 @@ import type {PaddingOptions, LngLat, Point, LngLatLike, PointLike} from './common'; +import type {Projection} from './style-spec'; export interface IControl { 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 & { diff --git a/src/utils/transform.ts b/src/utils/transform.ts index 4c46849ef..5f5cefe37 100644 --- a/src/utils/transform.ts +++ b/src/utils/transform.ts @@ -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