UNPKG

@mapbox/react-map-gl

Version:

A React wrapper for MapboxGL-js and overlay API.

252 lines (208 loc) 8.14 kB
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; /* global requestAnimationFrame, cancelAnimationFrame */ import assert from './assert'; import { TransitionInterpolator, LinearInterpolator } from './transition'; import MapState from './map-state'; var noop = function noop() {}; // crops the old easing function from x0 to 1 where x0 is the interruption point // returns a new easing function with domain [0, 1] and range [0, 1] export function cropEasingFunction(easing, x0) { var y0 = easing(x0); return function (t) { return 1 / (1 - y0) * (easing(t * (1 - x0) + x0) - y0); }; } export var TRANSITION_EVENTS = { BREAK: 1, SNAP_TO_END: 2, IGNORE: 3, UPDATE: 4 }; var DEFAULT_PROPS = { transitionDuration: 0, transitionEasing: function transitionEasing(t) { return t; }, transitionInterpolator: new LinearInterpolator(), transitionInterruption: TRANSITION_EVENTS.BREAK, onTransitionStart: noop, onTransitionInterrupt: noop, onTransitionEnd: noop, onViewportChange: noop, onStateChange: noop }; var TransitionManager = /*#__PURE__*/ function () { function TransitionManager(props) { var _this = this; _classCallCheck(this, TransitionManager); _defineProperty(this, "props", void 0); _defineProperty(this, "state", void 0); _defineProperty(this, "_animationFrame", null); _defineProperty(this, "_onTransitionFrame", function () { // _updateViewport() may cancel the animation _this._animationFrame = requestAnimationFrame(_this._onTransitionFrame); _this._updateViewport(); }); if (props) { this.props = props; } } _createClass(TransitionManager, [{ key: "getViewportInTransition", // Returns current transitioned viewport. value: function getViewportInTransition() { return this._animationFrame ? this.state.propsInTransition : null; } // Process the viewport change, either ignore or trigger a new transiton. // Return true if a new transition is triggered, false otherwise. }, { key: "processViewportChange", value: function processViewportChange(nextProps) { var currentProps = this.props; // Set this.props here as '_triggerTransition' calls '_updateViewport' that uses this.props. this.props = nextProps; // NOTE: Be cautious re-ordering statements in this function. if (this._shouldIgnoreViewportChange(currentProps, nextProps)) { return false; } if (this._isTransitionEnabled(nextProps)) { var startProps = Object.assign({}, currentProps); var endProps = Object.assign({}, nextProps); if (this._isTransitionInProgress()) { currentProps.onTransitionInterrupt(); if (this.state.interruption === TRANSITION_EVENTS.SNAP_TO_END) { Object.assign(startProps, this.state.endProps); } else { Object.assign(startProps, this.state.propsInTransition); } if (this.state.interruption === TRANSITION_EVENTS.UPDATE) { var currentTime = Date.now(); var x0 = (currentTime - this.state.startTime) / this.state.duration; endProps.transitionDuration = this.state.duration - (currentTime - this.state.startTime); endProps.transitionEasing = cropEasingFunction(this.state.easing, x0); endProps.transitionInterpolator = startProps.transitionInterpolator; } } endProps.onTransitionStart(); this._triggerTransition(startProps, endProps); return true; } if (this._isTransitionInProgress()) { currentProps.onTransitionInterrupt(); this._endTransition(); } return false; } // Helper methods }, { key: "_isTransitionInProgress", value: function _isTransitionInProgress() { return Boolean(this._animationFrame); } }, { key: "_isTransitionEnabled", value: function _isTransitionEnabled(props) { return props.transitionDuration > 0 && Boolean(props.transitionInterpolator); } }, { key: "_isUpdateDueToCurrentTransition", value: function _isUpdateDueToCurrentTransition(props) { if (this.state.propsInTransition) { return this.state.interpolator.arePropsEqual(props, this.state.propsInTransition); } return false; } }, { key: "_shouldIgnoreViewportChange", value: function _shouldIgnoreViewportChange(currentProps, nextProps) { if (!currentProps) { return true; } if (this._isTransitionInProgress()) { // Ignore update if it is requested to be ignored return this.state.interruption === TRANSITION_EVENTS.IGNORE || // Ignore update if it is due to current active transition. this._isUpdateDueToCurrentTransition(nextProps); } if (this._isTransitionEnabled(nextProps)) { // Ignore if none of the viewport props changed. return nextProps.transitionInterpolator.arePropsEqual(currentProps, nextProps); } return true; } }, { key: "_triggerTransition", value: function _triggerTransition(startProps, endProps) { assert(this._isTransitionEnabled(endProps), 'Transition is not enabled'); if (this._animationFrame) { cancelAnimationFrame(this._animationFrame); } var initialProps = endProps.transitionInterpolator.initializeProps(startProps, endProps); var interactionState = { inTransition: true, isZooming: startProps.zoom !== endProps.zoom, isPanning: startProps.longitude !== endProps.longitude || startProps.latitude !== endProps.latitude, isRotating: startProps.bearing !== endProps.bearing || startProps.pitch !== endProps.pitch }; this.state = { // Save current transition props duration: endProps.transitionDuration, easing: endProps.transitionEasing, interpolator: endProps.transitionInterpolator, interruption: endProps.transitionInterruption, startTime: Date.now(), startProps: initialProps.start, endProps: initialProps.end, animation: null, propsInTransition: {}, interactionState: interactionState }; this._onTransitionFrame(); this.props.onStateChange(interactionState); } }, { key: "_endTransition", value: function _endTransition() { if (this._animationFrame) { cancelAnimationFrame(this._animationFrame); this._animationFrame = null; } this.props.onStateChange({ inTransition: false, isZooming: false, isPanning: false, isRotating: false }); } }, { key: "_updateViewport", value: function _updateViewport() { // NOTE: Be cautious re-ordering statements in this function. var currentTime = Date.now(); var _this$state = this.state, startTime = _this$state.startTime, duration = _this$state.duration, easing = _this$state.easing, interpolator = _this$state.interpolator, startProps = _this$state.startProps, endProps = _this$state.endProps; var shouldEnd = false; var t = (currentTime - startTime) / duration; if (t >= 1) { t = 1; shouldEnd = true; } t = easing(t); var viewport = interpolator.interpolateProps(startProps, endProps, t); // Normalize viewport props var mapState = new MapState(Object.assign({}, this.props, viewport)); this.state.propsInTransition = mapState.getViewportProps(); this.props.onViewportChange(this.state.propsInTransition, this.state.interactionState, this.props); if (shouldEnd) { this._endTransition(); this.props.onTransitionEnd(); } } }]); return TransitionManager; }(); _defineProperty(TransitionManager, "defaultProps", DEFAULT_PROPS); export { TransitionManager as default }; //# sourceMappingURL=transition-manager.js.map