UNPKG

azure-maps-animations

Version:

A module for the Azure Maps Web SDK that provides tools for animating data on the map.

1,142 lines (1,124 loc) 199 kB
/* MIT License Copyright (c) Microsoft Corporation. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE */ (function (exports, azmaps) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; /** * Helper class for merging namespaces. */ var Namespace = /** @class */ (function () { function Namespace() { } Namespace.merge = function (namespace, base) { var context = window || global; var parts = namespace.split("."); for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) { var part = parts_1[_i]; if (context[part]) { context = context[part]; } else { return base; } } return __assign(__assign({}, context), base); }; return Namespace; }()); /** Easing functions for animations. */ var Easings = /** @class */ (function () { function Easings() { } //From http://andrewraycode.github.io/easing-utils/gh-pages/ /** * A linear easing function. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.linear = function (progress) { return progress; }; /** * Slight acceleration from zero to full speed. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInSine = function (progress) { return 1 - Math.cos(progress * Math.PI * 0.5); }; /** * Slight deceleration at the end. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutSine = function (progress) { return Math.sin(progress * Math.PI * 0.5); }; /** * Slight acceleration at beginning and slight deceleration at end. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutSine = function (progress) { return -0.5 * (Math.cos(Math.PI * progress) - 1); }; /** * Accelerating from zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInQuad = function (progress) { return progress * progress; }; /** * Decelerating to zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutQuad = function (progress) { return progress * (2 - progress); }; /** * Acceleration until halfway, then deceleration. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutQuad = function (progress) { if (progress < 0.5) { return 2 * progress * progress; } return -1 + (4 - 2 * progress) * progress; }; /** * Accelerating from zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInCubic = function (progress) { return progress * progress * progress; }; /** * Decelerating to zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutCubic = function (progress) { var t1 = progress - 1; return t1 * t1 * t1 + 1; }; /** * Acceleration until halfway, then deceleration. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutCubic = function (progress) { if (progress < 0.5) { return 4 * progress * progress * progress; } return (progress - 1) * (2 * progress - 2) * (2 * progress - 2) + 1; }; /** * Accelerating from zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInQuart = function (progress) { return progress * progress * progress * progress; }; /** * Decelerating to zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutQuart = function (progress) { var t1 = progress - 1; return 1 - t1 * t1 * t1 * t1; }; /** * Acceleration until halfway, then deceleration. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutQuart = function (progress) { if (progress < 0.5) { return 8 * progress * progress * progress * progress; } var t1 = progress - 1; return 1 - 8 * t1 * t1 * t1 * t1; }; /** * Accelerating from zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInQuint = function (progress) { return progress * progress * progress * progress * progress; }; /** * Decelerating to zero velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutQuint = function (progress) { var t1 = progress - 1; return 1 + t1 * t1 * t1 * t1 * t1; }; /** * Acceleration until halfway, then deceleration. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutQuint = function (progress) { if (progress < 0.5) { return 16 * progress * progress * progress * progress * progress; } var t1 = progress - 1; return 1 + 16 * t1 * t1 * t1 * t1 * t1; }; /** * Accelerate exponentially until finish. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInExpo = function (progress) { if (progress === 0) { return 0; } return Math.pow(2, 10 * (progress - 1)); }; /** * Initial exponential acceleration slowing to stop. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutExpo = function (progress) { if (progress === 1) { return 1; } return 1 - Math.pow(2, -10 * progress); }; /** * Exponential acceleration and deceleration. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutExpo = function (progress) { if (progress === 0 || progress === 1) { return progress; } var scaledTime1 = progress * 2 - 1; if (scaledTime1 < 0) { return 0.5 * Math.pow(2, 10 * scaledTime1); } return 0.5 * (2 - Math.pow(2, -10 * scaledTime1)); }; /** * Increasing velocity until stop. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInCirc = function (progress) { return -1 * (Math.sqrt(1 - progress * progress) - 1); }; /** * Start fast, decreasing velocity until stop. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutCirc = function (progress) { var t1 = progress - 1; return Math.sqrt(1 - t1 * t1); }; /** * Fast increase in velocity, fast decrease in velocity. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutCirc = function (progress) { var scaledTime = progress * 2; if (scaledTime < 1) { return -0.5 * (Math.sqrt(1 - scaledTime * scaledTime) - 1); } var scaledTime1 = scaledTime - 2; return 0.5 * (Math.sqrt(1 - scaledTime1 * scaledTime1) + 1); }; /** * Slow movement backwards then fast snap to finish. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeInBack = function (progress, magnitude) { magnitude = magnitude || 1.70158; return progress * progress * ((magnitude + 1) * progress - magnitude); }; /** * Fast snap to backwards point then slow resolve to finish. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeOutBack = function (progress, magnitude) { magnitude = magnitude || 1.70158; var scaledTime = progress - 1; return (scaledTime * scaledTime * ((magnitude + 1) * scaledTime + magnitude)) + 1; }; /** * Slow movement backwards, fast snap to past finish, slow resolve to finish. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeInOutBack = function (progress, magnitude) { magnitude = magnitude || 1.70158; var scaledTime = progress * 2; var s = magnitude * 1.525; if (scaledTime < 1) { return 0.5 * scaledTime * scaledTime * (((s + 1) * scaledTime) - s); } var scaledTime2 = scaledTime - 2; return 0.5 * (scaledTime2 * scaledTime2 * ((s + 1) * scaledTime2 + s) + 2); }; /** * Bounces slowly then quickly to finish. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeInElastic = function (progress, magnitude) { if (progress === 0 || progress === 1) { return progress; } magnitude = magnitude || 0.7; var scaledTime1 = progress - 1; var p = 1 - magnitude; var s = p / (2 * Math.PI) * Math.asin(1); return -(Math.pow(2, 10 * scaledTime1) * Math.sin((scaledTime1 - s) * (2 * Math.PI) / p)); }; /** * Fast acceleration, bounces to zero. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeOutElastic = function (progress, magnitude) { if (progress === 0 || progress === 1) { return progress; } magnitude = magnitude || 0.7; var p = 1 - magnitude; var scaledTime = progress * 2; var s = p / (2 * Math.PI) * Math.asin(1); return (Math.pow(2, -10 * scaledTime) * Math.sin((scaledTime - s) * (2 * Math.PI) / p)) + 1; }; /** * Slow start and end, two bounces sandwich a fast motion. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. * @param magnitude The magnitude of the easing. */ Easings.easeInOutElastic = function (progress, magnitude) { if (progress === 0 || progress === 1) { return progress; } magnitude = magnitude || 0.65; var p = 1 - magnitude; var scaledTime1 = progress * 2 - 1; var s = p / (2 * Math.PI) * Math.asin(1); if (scaledTime1 < 0) { return -0.5 * (Math.pow(2, 10 * scaledTime1) * Math.sin((scaledTime1 - s) * (2 * Math.PI) / p)); } return (Math.pow(2, -10 * scaledTime1) * Math.sin((scaledTime1 - s) * (2 * Math.PI) / p) * 0.5) + 1; }; /** * Bounce to completion. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeOutBounce = function (progress) { if (progress < (1 / 2.75)) { return 7.5625 * progress * progress; } else if (progress < (2 / 2.75)) { var scaledTime2 = progress - (1.5 / 2.75); return (7.5625 * scaledTime2 * scaledTime2) + 0.75; } else if (progress < (2.5 / 2.75)) { var scaledTime2 = progress - (2.25 / 2.75); return (7.5625 * scaledTime2 * scaledTime2) + 0.9375; } else { var scaledTime2 = progress - (2.625 / 2.75); return (7.5625 * scaledTime2 * scaledTime2) + 0.984375; } }; /** * Bounce increasing in velocity until completion. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInBounce = function (progress) { return 1 - Easings.easeOutBounce(1 - progress); }; /** * Bounce in and bounce out. * @param progress The progress of the animation. A value between 0 and 1 where 0 is the start of the animation and 1 is the end. */ Easings.easeInOutBounce = function (progress) { if (progress < 0.5) { return Easings.easeInBounce(progress * 2) * 0.5; } return (Easings.easeOutBounce((progress * 2) - 1) * 0.5) + 0.5; }; return Easings; }()); var Utils = /** @class */ (function () { function Utils() { } /** * Calculates the progress of an animation based on the current timestamp, start time and duration. * @param timestamp The current timestamp. * @param start The time the animation started. * @param duration The duration of the animation. * @param speed The speed of the animation. */ Utils.getProgress = function (timestamp, start, duration, speed) { return Math.max(Math.min((timestamp - start) * speed / duration, 1), 0); }; /** * Calculates the start time of an animation based on the progress and duration. * @param progress Progress of an animation. * @param duration Duration of an animation. * @param speed The speed of the animation. */ Utils.getStartTime = function (progress, duration, speed) { return performance.now() - Math.round((duration * progress) / speed); }; /** * * @param coords The coordinate set. * @returns 0 - point, 1 - linestring/multipoint, 2 - polygon/multilinestring, 3 - multipolygon. */ Utils.getDimensions = function (coords) { if (coords && Array.isArray(coords) && coords.length > 0) { if (typeof coords[0] === 'number') { return 0; //Point } else if (Array.isArray(coords[0]) && coords[0].length > 0) { if (typeof coords[0][0] === 'number') { return 1; //MultiPoint or Linestring } else if (Array.isArray(coords[0][0]) && coords[0][0].length > 0) { if (typeof coords[0][0][0] === 'number') { return 2; //polygon or multilinestring } else if (Array.isArray(coords[0][0][0]) && coords[0][0][0].length > 0) { if (typeof coords[0][0][0][0] === 'number') { return 3; //MultiPolygon } } } } } return -1; }; Utils.getSuitableCoordinates = function (shape, coords) { var geomType = 'Point'; if (shape instanceof azmaps.Shape) { geomType = shape.getType(); } if (coords) { var dim = Utils.getDimensions(coords); switch (geomType) { case 'Point': switch (dim) { case 0: return coords; case 1: return coords[0]; case 2: return coords[0][0]; case 3: return coords[0][0][0]; } break; case 'MultiPoint': case 'LineString': switch (dim) { case 0: return (geomType === 'MultiPoint') ? [coords] : [coords, coords]; case 1: return coords; case 2: return coords[0]; case 3: return coords[0][0]; } break; case 'MultiLineString': case 'Polygon': switch (dim) { case 0: return [[coords, coords, coords]]; case 1: return [coords]; case 2: return coords; case 3: return coords[0]; } break; case 'MultiPolygon': switch (dim) { case 0: return [[[coords, coords, coords]]]; case 1: return [[coords]]; case 2: return [coords]; case 3: return coords; } break; } } return null; }; Utils.getPixelHeading = function (origin, destination) { var dx = (destination[0] - origin[0]) * Math.PI / 180; var dy = (origin[1] - destination[1]) * Math.PI / 180; return ((5 / 2 * Math.PI) - Math.atan2(dy, dx)) * 180 / Math.PI % 360; }; Utils.getPixelDestination = function (origin, heading, distance) { return [ origin[0] + distance * Math.cos((heading + 270) * Math.PI / 180), origin[1] + distance * Math.sin((heading + 270) * Math.PI / 180), ]; }; /** Adds metadata to a shape. */ Utils.setMetadata = function (shape, metadata) { if (shape && metadata) { if (shape instanceof azmaps.Shape) { shape.setProperties(Object.assign(shape.getProperties(), metadata)); } else if (shape instanceof azmaps.HtmlMarker) { shape['metadata'] = Object.assign(shape['metadata'] || {}, metadata); } } }; /** Updates the coordinates of a point or line shape, or an HTML marker. */ Utils.setCoordinates = function (shape, pos, positions) { if (shape) { if (shape instanceof azmaps.Shape) { switch (shape.getType()) { case 'Point': shape.setCoordinates(pos); break; case 'LineString': if (positions) { shape.setCoordinates(positions); } break; } } else if (shape instanceof azmaps.HtmlMarker) { shape.setOptions({ position: pos }); } } }; /** * Takes a formatted property path string, and breaks it up into its parts. * @param path Property path string. */ Utils.getPropertyPath = function (path) { return path.split('/'); }; /** * Sets a value on an object based on property path. * @param obj The object to add the value to. * @param propertyPath The path to the property. * @param value The value. */ Utils.setValue = function (obj, propertyPath, value) { if (propertyPath.length > 1) { var key = propertyPath.shift(); Utils.setValue(obj[key] = Object.prototype.toString.call(obj[key]) === '[object Object]' ? obj[key] : {}, propertyPath, value); } else { obj[propertyPath[0]] = value; } }; /** * Retrieves the value of an object using its path. * @param obj The object to get the value from. * @param propertyPath The path of the property. */ Utils.getValue = function (obj, propertyPath) { var len = propertyPath.length; if (len > 0 && obj) { var o = obj[propertyPath[0]]; if (o != null) { var i = void 0; // Step through the property. for (i = 1; i < len; i++) { o = o[propertyPath[i]]; if (o == null) { break; } } // Make sure that all properties were stepped through. if (i === len && o != null) { return o; } } } return null; }; /** * Grabs the properties of two points and performs an interpolation between them. * @param p1 The first point feature. * @param p2 The second point feature. * @param offset The offset between the first point and the second point. * @param intpr The interpolation expression. */ Utils.interpolateValue = function (p1, p2, offset, intpr, obj) { if (p1 && p2 && intpr) { intpr.interpolation = intpr.interpolation || 'linear'; var propertyPath = Utils.getPropertyPath(intpr.propertyPath); var v1 = Utils.getValue(p1.properties, propertyPath); var v2 = Utils.getValue(p2.properties, propertyPath); var t1 = typeof v1; var t2 = typeof v2; if (t1 !== 'undefined' && t2 !== 'undefined' && t1 === t2) { var tOut = void 0; if (v1 instanceof Date) { v1 = v1.getTime(); tOut = 'Date'; } if (v2 instanceof Date) { v2 = v2.getTime(); //If tOut is not set to date, v1 is a different type. if (tOut !== 'Date') { return null; } } var val = void 0; if (t1 === 'number' && t2 === 'number') { switch (intpr.interpolation) { case 'linear': val = v1 + (v2 - v1) * offset; break; case 'min': val = Math.min(v1, v2); break; case 'max': val = Math.max(v1, v2); break; case 'avg': val = (v1 + v2) * 0.5; break; } } else if (intpr.interpolation === 'nearest') { val = (offset < 0.5) ? v1 : v2; } if (typeof val !== 'undefined') { if (tOut === 'Date') { val = new Date(val); } Utils.setValue(obj, propertyPath, val); } } } return null; }; Utils.extractRoutePointsFromFeature = function (feature, timestampProperty) { var pts = []; var pt; var t; switch (feature.geometry.type) { case 'Point': pt = Utils.extractRoutePointFromPoint(feature, timestampProperty); if (pt) { pts = [pt]; } break; case 'LineString': case 'MultiPoint': if (feature.properties[timestampProperty] && Array.isArray(feature.properties[timestampProperty]) && feature.geometry.coordinates.length === feature.properties[timestampProperty]) { for (var i = 0, len = feature.geometry.coordinates.length; i < len; i++) { t = azmaps.math.parseTimestamp(feature.properties[timestampProperty]); if (t) { pts.push(new azmaps.data.Feature(new azmaps.data.Point(feature.geometry.coordinates[i]), { _timestamp: t.getTime() })); } } } //Check to see if the feature has waypoints in its properties which may contain the route point info. else if (feature.properties.waypoints && Array.isArray(feature.properties.waypoints) && feature.geometry.coordinates.length === feature.properties.waypoints.length && feature.properties.waypoints.length > 0 && feature.properties.waypoints[0].geometry) { for (var i = 0, len = feature.geometry.coordinates.length; i < len; i++) { if (feature.properties.waypoints[i].geometry.type === 'Point') { pt = Utils.extractRoutePointFromPoint(feature.properties.waypoints[i], timestampProperty); if (pt) { pts.push(pt); } } } } break; } if (pts.length > 0) { return pts; } return null; }; Utils.extractRoutePointFromPoint = function (feature, timestampProperty) { //Check to see if the feature has the timestampProperty. if (feature.properties[timestampProperty]) { var t = azmaps.math.parseTimestamp(feature.properties[timestampProperty]); if (typeof t !== 'undefined') { feature.properties._timestamp = t.getTime(); return feature; } } return null; }; return Utils; }()); /** An animation manager for classes that extend from the AnimatedShape class. */ var AnimationManager = /** @class */ (function () { /**************************** * Constructor ***************************/ function AnimationManager() { /**************************** * Private Properties ***************************/ this._animation = null; this._queue = []; //Min frame rate this._minFR = 33; //roughly 30 frames per second is the fastest that the animation loop will update. this._stopped = true; this._idCounter = 1234567890; this._idTable = {}; this._lastTime = performance.now(); this.enable(); } /**************************** * Public functions ***************************/ /** Stops all animations. */ AnimationManager.prototype.disable = function () { var self = this; if (!self._stopped) { self._stopped = true; cancelAnimationFrame(self._animation); } }; /** Renables animations. Many will likely snap to the end of their animation. */ AnimationManager.prototype.enable = function () { var self = this; if (self._stopped) { self._stopped = false; self._animation = requestAnimationFrame(self._animate.bind(self)); } }; /** * Adds an animated object to the animation queue. * @param animatable The object to animate. */ AnimationManager.prototype.add = function (animatable) { var self = this; if (!animatable._id) { animatable._id = self._getUuid(); } var animation = self._idTable[animatable._id]; //Only add the animation to the queue if it isn't already in it. if (!animation) { self._queue.push(animatable); self._idTable[animatable._id] = animatable; } return animatable._id; }; /** * Gets an animation by ID. * @param id The ID of the animation to get. */ AnimationManager.prototype.getById = function (id) { return this._idTable[id]; }; /** * Removes a object from the animation queue. * @param animatable The object to remove from the queue. */ AnimationManager.prototype.remove = function (animatable) { var self = this; //Verify animation is in queue. if (animatable) { var id = animatable._id; if (self._idTable[id]) { var q = self._queue; //Loop through and find the index of the animation in the array. for (var i = q.length - 1; i >= 0; i--) { if (id === q[i]._id) { //Remove it from the queue. self._queue = q.splice(i, 1); //Remove it from the lookup table. self._idTable[id] = undefined; break; } } } } }; /** * Removes an animation from the queue by ID. * @param id The ID of the animation to remove. */ AnimationManager.prototype.removeById = function (id) { this.remove(this._idTable[id]); }; /**************************** * Private functions ***************************/ /** Loops through the queue and animates a frame for each animatable object. */ AnimationManager.prototype._animate = function () { var self = this; if (!self._stopped) { var t = performance.now(); if (t - self._lastTime >= self._minFR) { var q = self._queue; //Iterate backwards over queue incase the _onTriggerFrameAnimation asks to remove the animation. for (var i = q.length - 1; i >= 0; i--) { try { q[i]._onAnimationProgress(t); } catch (_a) { } } //Request the next frame of the animation. self._lastTime = t; } self._animation = requestAnimationFrame(self._animate.bind(self)); } }; /** Retrieves a unique ID from the animation manager. */ AnimationManager.prototype._getUuid = function () { return this._idCounter++; }; /**************************** * Public static properties ***************************/ /** A blobal static instance of the AnimationManager. */ AnimationManager.instance = new AnimationManager(); return AnimationManager; }()); /** An abstract class which defines an animation that supports a play function. */ var PlayableAnimation = /** @class */ (function (_super) { __extends(PlayableAnimation, _super); /************************** * Constructor ***************************/ /** * The base playable animation class. * @param options Animaiton options. */ function PlayableAnimation(options) { var _this = _super.call(this) || this; /************************** * Private properties ***************************/ _this._start = null; _this._rawProgress = 0; _this._options = { duration: 1000, autoPlay: false, easing: 'linear', loop: false, reverse: false, speedMultiplier: 1, disposeOnComplete: false }; _this._easing = Easings.linear; var self = _this; self._id = AnimationManager.instance.add(self); self.setOptions(options); return _this; } /************************** * Public Methods ***************************/ /** Disposes the animation. */ PlayableAnimation.prototype.dispose = function () { var self = this; self.stop(); AnimationManager.instance.remove(self); self._options = null; self._easing = null; self._start = null; self._onComplete = null; self._id = undefined; self._rawProgress = null; }; /** Gets the duration of the animation. Returns Infinity if the animations loops forever. */ PlayableAnimation.prototype.getDuration = function () { var o = this._options; return (o.loop) ? Infinity : o.duration / o.speedMultiplier; }; /** Gets the animation options. */ PlayableAnimation.prototype.getOptions = function () { return Object.assign({}, this._options); }; /** * Checks to see if the animaiton is playing. */ PlayableAnimation.prototype.isPlaying = function () { return this._start !== null; }; /** * Plays the animation. */ PlayableAnimation.prototype.play = function () { var self = this; if (self._rawProgress >= 1) { //Animation is complete, restart. self._rawProgress = 0; } if (self._rawProgress > 0) { //Animation is paused, calculated offset start time of animation. self._start = Utils.getStartTime(self._rawProgress, self._options.duration, self._options.speedMultiplier); } else { self._start = performance.now(); } }; /** * Pauses the animation. */ PlayableAnimation.prototype.pause = function () { //Stop the progress of the animation. this._start = null; }; /** * Advances the animation to specific step. * @param progress The progress of the animation to advance to. A value between 0 and 1. */ PlayableAnimation.prototype.seek = function (progress) { var self = this; if (typeof progress === 'number') { var isPLaying = self.isPlaying(); if (isPLaying) { self.pause(); } self._rawProgress = Math.min(Math.max(progress, 0), 1) / self._options.speedMultiplier; self._processFrame(); if (isPLaying) { self.play(); } } }; /** Sets the options of the animation. */ PlayableAnimation.prototype.setOptions = function (options) { if (options) { var self_1 = this; var opt = self_1._options; if (options.easing) { if (typeof options.easing === 'string' && Easings[options.easing]) { self_1._easing = Easings[options.easing]; opt.easing = options.easing; } else if (options.easing instanceof Function) { self_1._easing = options.easing; opt.easing = options.easing; } } if (typeof options.loop === 'boolean') { opt.loop = options.loop; } if (typeof options.disposeOnComplete === 'boolean') { opt.disposeOnComplete = options.disposeOnComplete; } if (typeof options.reverse === 'boolean') { opt.reverse = options.reverse; } if (typeof options.speedMultiplier === 'number' && options.speedMultiplier > 0) { opt.speedMultiplier = options.speedMultiplier; } var hasDuration = typeof options.duration === 'number' && options.duration > 0 && opt.duration !== options.duration; var hasAutoPlay = typeof options.autoPlay === 'boolean'; if (hasDuration || hasAutoPlay) { var isPlaying = self_1.isPlaying(); if (isPlaying) { self_1.pause(); } if (hasAutoPlay) { opt.autoPlay = options.autoPlay || opt.autoPlay; if (!isPlaying && options.autoPlay) { isPlaying = true; } } if (hasDuration) { opt.duration = options.duration || opt.duration; } if (isPlaying) { self_1.play(); } } } }; /** * Stops the animation and jumps back to the end of the animation. */ PlayableAnimation.prototype.stop = function () { var self = this; //Jump to the end of the animation. self._rawProgress = 1; self._processFrame(); self._start = null; }; /** * Stops the animation and jumps back to the beginning of the animation. */ PlayableAnimation.prototype.reset = function () { var self = this; //Jump to the beginning of the animation. self._start = null; self._rawProgress = 0; self._processFrame(); }; /** * Callback function that contains the animation frame logic. * @param progress The progress of the animation where 0 is start and 1 is the end. */ PlayableAnimation.prototype._onAnimationProgress = function (timestamp) { var self = this; if (self._start) { self._rawProgress = Utils.getProgress(timestamp, self._start, self._options.duration, self._options.speedMultiplier); self._processFrame(); } }; /************************** * Private functions ***************************/ /** * Processes the animation frame for the raw progress. */ PlayableAnimation.prototype._processFrame = function () { var self = this; var opt = self._options; if (typeof self._id !== 'undefined') { var progress = self._rawProgress || 0; //Animation reached the end. if (progress >= 1) { if (opt.loop) { //Restart the animation. self._rawProgress = 0; self._start = performance.now(); } else { //Stop animating. self._rawProgress = 1; self._start = null; if (self._onComplete) { self._onComplete(); } } } var playProgress = (opt.reverse) ? 1 - self._rawProgress : self._rawProgress; if (self._easing) { progress = self._easing(playProgress); } var state = self.onAnimationProgress(progress); var eventArgs = Object.assign({ progress: playProgress, easingProgress: progress, animation: self }, state || {}); self._invokeEvent('onprogress', Object.assign({ type: 'onprogress' }, eventArgs)); //Check to see if the animation is complete. if (self._start === null) { self._invokeEvent('oncomplete', Object.assign({ type: 'oncomplete' }, eventArgs)); } if (opt.disposeOnComplete) { self.dispose(); } } }; return PlayableAnimation; }(azmaps.internal.EventEmitter)); /** A class for frame based animations. */ var FrameBasedAnimationTimer = /** @class */ (function (_super) { __extends(FrameBasedAnimationTimer, _super); /** * An class for frame based animations. * @param numberOfFrames The number of frames in the animation. * @param onFrame A callback function to trigger when the frame index changes. * @param options Animation options. */ function FrameBasedAnimationTimer(numberOfFrames, onFrame, options) { var _this = _super.call(this, options) || this; _this._numFrames = 0; _this._curFrameIdx = -1; var self = _this; self._numFrames = numberOfFrames; self._onFrame = onFrame; if (options && options.autoPlay) { self.play(); } return _this; } /** Gets the current frame index of the animation. Returns -1 if animation hasn't started, or if there is 0 frames. */ FrameBasedAnimationTimer.prototype.getCurrentFrameIdx = function () { if (this._numFrames <= 0) { return -1; } return this._curFrameIdx; }; /** Gets the number of frames in the animation. */ FrameBasedAnimationTimer.prototype.getNumberOfFrames = function () { return this._numFrames; }; /** * Sets the frame index of the animation. * @param frameIdx The frame index to advance to. */ FrameBasedAnimationTimer.prototype.setFrameIdx = function (frameIdx) { var self = this; if (frameIdx >= 0 || frameIdx < self._numFrames) { self.seek(self._numFrames / frameIdx); } }; /**