UNPKG

@mapbox/react-map-gl

Version:

A React wrapper for MapboxGL-js and overlay API.

101 lines (81 loc) 2.98 kB
// @flow import WebMercatorViewport from 'viewport-mercator-project'; import assert from '../assert'; import TransitionInterpolator from './transition-interpolator'; import {isValid, getEndValueByShortestPath} from './transition-utils'; import {lerp} from '../math-utils'; import type {MapStateProps} from '../map-state'; const VIEWPORT_TRANSITION_PROPS = ['longitude', 'latitude', 'zoom', 'bearing', 'pitch']; type TransitionProps = MapStateProps & { around: Array<number>, aroundLngLat: Array<number> }; /** * Performs linear interpolation of two viewports. */ export default class LinearInterpolator extends TransitionInterpolator { /** * @param opts {Object} * - opts.transitionProps {Array}] - list of props to apply linear transition to. * - opts.around {Array} - a screen point to zoom/rotate around */ constructor(opts: { transitionProps?: Array<string>, around?: Array<number> } = {}) { super(); if (Array.isArray(opts)) { // backward compatibility opts = {transitionProps: opts}; } this.propNames = opts.transitionProps || VIEWPORT_TRANSITION_PROPS; if (opts.around) { this.around = opts.around; } } around: Array<number>; initializeProps(startProps: MapStateProps, endProps: MapStateProps) { const startViewportProps = {}; const endViewportProps = {}; if (this.around) { // anchor point in origin screen coordinates startViewportProps.around = this.around; // anchor point in spherical coordinates const aroundLngLat = new WebMercatorViewport(startProps).unproject(this.around); Object.assign(endViewportProps, endProps, { // anchor point in destination screen coordinates around: new WebMercatorViewport(endProps).project(aroundLngLat), aroundLngLat }); } for (const key of this.propNames) { const startValue = startProps[key]; const endValue = endProps[key]; assert(isValid(startValue) && isValid(endValue), `${key} must be supplied for transition`); startViewportProps[key] = startValue; endViewportProps[key] = getEndValueByShortestPath(key, startValue, endValue); } return { start: startViewportProps, end: endViewportProps }; } interpolateProps(startProps: TransitionProps, endProps: TransitionProps, t: number) { const viewport = {}; for (const key of this.propNames) { viewport[key] = lerp(startProps[key], endProps[key], t); } if (endProps.around) { // zoom around provided point const [longitude, latitude] = new WebMercatorViewport(Object.assign({}, endProps, viewport)) .getMapCenterByLngLatPosition({ lngLat: endProps.aroundLngLat, // anchor point in current screen coordinates pos: lerp(startProps.around, endProps.around, t) }); viewport.longitude = longitude; viewport.latitude = latitude; } return viewport; } }