timescale.js (4581B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 getFormatStr, 9 } = require("resource://devtools/client/inspector/animation/utils/l10n.js"); 10 11 // If total duration for all animations is eqaul to or less than 12 // TIME_FORMAT_MAX_DURATION_IN_MS, the text which expresses time is in milliseconds, 13 // and seconds otherwise. Use in formatTime function. 14 const TIME_FORMAT_MAX_DURATION_IN_MS = 4000; 15 16 /** 17 * TimeScale object holds the total duration, start time and end time and zero position 18 * time information for all animations which should be displayed, and is used to calculate 19 * the displayed area for each animation. 20 */ 21 class TimeScale { 22 constructor(animations) { 23 let resultCurrentTime = -Number.MAX_VALUE; 24 let resultMinStartTime = Infinity; 25 let resultMaxEndTime = 0; 26 let resultZeroPositionTime = 0; 27 28 for (const animation of animations) { 29 const { 30 currentTime, 31 currentTimeAtCreated, 32 delay, 33 endTime, 34 startTimeAtCreated, 35 } = animation.state.absoluteValues; 36 let { startTime } = animation.state.absoluteValues; 37 38 const negativeDelay = Math.min(delay, 0); 39 let zeroPositionTime = 0; 40 41 // To shift the zero position time is the following two patterns. 42 // * Animation has negative current time which is smaller than negative delay. 43 // * Animation has negative delay. 44 // Furthermore, we should override the zero position time if we will need to 45 // expand the duration due to this negative current time or negative delay of 46 // this target animation. 47 if (currentTimeAtCreated < negativeDelay) { 48 startTime = startTimeAtCreated; 49 zeroPositionTime = Math.abs(currentTimeAtCreated); 50 } else if (negativeDelay < 0) { 51 zeroPositionTime = Math.abs(negativeDelay); 52 } 53 54 if (startTime < resultMinStartTime) { 55 resultMinStartTime = startTime; 56 // Override the previous calculated zero position only if the duration will be 57 // expanded. 58 resultZeroPositionTime = zeroPositionTime; 59 } else { 60 resultZeroPositionTime = Math.max( 61 resultZeroPositionTime, 62 zeroPositionTime 63 ); 64 } 65 66 resultMaxEndTime = Math.max(resultMaxEndTime, endTime); 67 resultCurrentTime = Math.max(resultCurrentTime, currentTime); 68 } 69 70 this.minStartTime = resultMinStartTime; 71 this.maxEndTime = resultMaxEndTime; 72 this.currentTime = resultCurrentTime; 73 this.zeroPositionTime = resultZeroPositionTime; 74 } 75 76 /** 77 * Convert a distance in % to a time, in the current time scale. The time 78 * will be relative to the zero position time. 79 * i.e., If zeroPositionTime will be negative and specified time is shorter 80 * than the absolute value of zero position time, relative time will be 81 * negative time. 82 * 83 * @param {number} distance 84 * @return {number} 85 */ 86 distanceToRelativeTime(distance) { 87 return (this.getDuration() * distance) / 100 - this.zeroPositionTime; 88 } 89 90 /** 91 * Depending on the time scale, format the given time as milliseconds or 92 * seconds. 93 * 94 * @param {number} time 95 * @return {string} The formatted time string. 96 */ 97 formatTime(time) { 98 // Ignore negative zero 99 if (Math.abs(time) < 1 / 1000) { 100 time = 0.0; 101 } 102 103 // Format in milliseconds if the total duration is short enough. 104 if (this.getDuration() <= TIME_FORMAT_MAX_DURATION_IN_MS) { 105 return getFormatStr("timeline.timeGraduationLabel", time.toFixed(0)); 106 } 107 108 // Otherwise format in seconds. 109 return getFormatStr("player.timeLabel", (time / 1000).toFixed(1)); 110 } 111 112 /** 113 * Return entire animations duration. 114 * 115 * @return {number} duration 116 */ 117 getDuration() { 118 return this.maxEndTime - this.minStartTime; 119 } 120 121 /** 122 * Return current time of this time scale represents. 123 * 124 * @return {number} 125 */ 126 getCurrentTime() { 127 return this.currentTime - this.minStartTime; 128 } 129 130 /** 131 * Return end time of given animation. 132 * This time does not include playbackRate and cratedTime. 133 * Also, if the animation has infinite iterations, this returns Infinity. 134 * 135 * @param {object} animation 136 * @return {Numbber} end time 137 */ 138 getEndTime({ state }) { 139 return state.iterationCount 140 ? state.delay + state.duration * state.iterationCount + state.endDelay 141 : Infinity; 142 } 143 } 144 145 module.exports = TimeScale;