wilderness-core
Version:
The SVG animation engine behind Wilderness
1,956 lines (1,651 loc) • 145 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.WildernessCore = {})));
}(this, (function (exports) { 'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var objectWithoutProperties = function (obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
};
var slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var toArray = function (arr) {
return Array.isArray(arr) ? arr : Array.from(arr);
};
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
};
/**
* A tweenable color.
*
* @typedef {Object} Color
*
* @property {string} middleware - The name of this middleware.
* @property {number} r - The hexadecimal red value.
* @property {number} g - The hexadecimal green value.
* @property {number} b - The hexadecimal blue value.
* @property {number} a - The alpha value.
*/
var name = 'color';
var htmlColors = {
'aliceblue': '#F0F8FF',
'antiquewhite': '#FAEBD7',
'aqua': '#00FFFF',
'aquamarine': '#7FFFD4',
'azure': '#F0FFFF',
'beige': '#F5F5DC',
'bisque': '#FFE4C4',
'black': '#000000',
'blanchedalmond': '#FFEBCD',
'blue': '#0000FF',
'blueviolet': '#8A2BE2',
'brown': '#A52A2A',
'burlywood': '#DEB887',
'cadetblue': '#5F9EA0',
'chartreuse': '#7FFF00',
'chocolate': '#D2691E',
'coral': '#FF7F50',
'cornflowerblue': '#6495ED',
'cornsilk': '#FFF8DC',
'crimson': '#DC143C',
'cyan': '#00FFFF',
'darkblue': '#00008B',
'darkcyan': '#008B8B',
'darkgoldenrod': '#B8860B',
'darkgray': '#A9A9A9',
'darkgreen': '#006400',
'darkgrey': '#A9A9A9',
'darkkhaki': '#BDB76B',
'darkmagenta': '#8B008B',
'darkolivegreen': '#556B2F',
'darkorange': '#FF8C00',
'darkorchid': '#9932CC',
'darkred': '#8B0000',
'darksalmon': '#E9967A',
'darkseagreen': '#8FBC8F',
'darkslateblue': '#483D8B',
'darkslategray': '#2F4F4F',
'darkslategrey': '#2F4F4F',
'darkturquoise': '#00CED1',
'darkviolet': '#9400D3',
'deeppink': '#FF1493',
'deepskyblue': '#00BFFF',
'dimgray': '#696969',
'dimgrey': '#696969',
'dodgerblue': '#1E90FF',
'firebrick': '#B22222',
'floralwhite': '#FFFAF0',
'forestgreen': '#228B22',
'fuchsia': '#FF00FF',
'gainsboro': '#DCDCDC',
'ghostwhite': '#F8F8FF',
'gold': '#FFD700',
'goldenrod': '#DAA520',
'gray': '#808080',
'green': '#008000',
'greenyellow': '#ADFF2F',
'grey': '#808080',
'honeydew': '#F0FFF0',
'hotpink': '#FF69B4',
'indianred': '#CD5C5C',
'indigo': '#4B0082',
'ivory': '#FFFFF0',
'khaki': '#F0E68C',
'lavender': '#E6E6FA',
'lavenderblush': '#FFF0F5',
'lawngreen': '#7CFC00',
'lemonchiffon': '#FFFACD',
'lightblue': '#ADD8E6',
'lightcoral': '#F08080',
'lightcyan': '#E0FFFF',
'lightgoldenrodyellow': '#FAFAD2',
'lightgray': '#D3D3D3',
'lightgreen': '#90EE90',
'lightgrey': '#D3D3D3',
'lightpink': '#FFB6C1',
'lightsalmon': '#FFA07A',
'lightseagreen': '#20B2AA',
'lightskyblue': '#87CEFA',
'lightslategray': '#778899',
'lightslategrey': '#778899',
'lightsteelblue': '#B0C4DE',
'lightyellow': '#FFFFE0',
'lime': '#00FF00',
'limegreen': '#32CD32',
'linen': '#FAF0E6',
'magenta': '#FF00FF',
'maroon': '#800000',
'mediumaquamarine': '#66CDAA',
'mediumblue': '#0000CD',
'mediumorchid': '#BA55D3',
'mediumpurple': '#9370DB',
'mediumseagreen': '#3CB371',
'mediumslateblue': '#7B68EE',
'mediumspringgreen': '#00FA9A',
'mediumturquoise': '#48D1CC',
'mediumvioletred': '#C71585',
'midnightblue': '#191970',
'mintcream': '#F5FFFA',
'mistyrose': '#FFE4E1',
'moccasin': '#FFE4B5',
'navajowhite': '#FFDEAD',
'navy': '#000080',
'oldlace': '#FDF5E6',
'olive': '#808000',
'olivedrab': '#6B8E23',
'orange': '#FFA500',
'orangered': '#FF4500',
'orchid': '#DA70D6',
'palegoldenrod': '#EEE8AA',
'palegreen': '#98FB98',
'paleturquoise': '#AFEEEE',
'palevioletred': '#DB7093',
'papayawhip': '#FFEFD5',
'peachpuff': '#FFDAB9',
'peru': '#CD853F',
'pink': '#FFC0CB',
'plum': '#DDA0DD',
'powderblue': '#B0E0E6',
'purple': '#800080',
'rebeccapurple': '#663399',
'red': '#FF0000',
'rosybrown': '#BC8F8F',
'royalblue': '#4169E1',
'saddlebrown': '#8B4513',
'salmon': '#FA8072',
'sandybrown': '#F4A460',
'seagreen': '#2E8B57',
'seashell': '#FFF5EE',
'sienna': '#A0522D',
'silver': '#C0C0C0',
'skyblue': '#87CEEB',
'slateblue': '#6A5ACD',
'slategray': '#708090',
'slategrey': '#708090',
'snow': '#FFFAFA',
'springgreen': '#00FF7F',
'steelblue': '#4682B4',
'tan': '#D2B48C',
'teal': '#008080',
'thistle': '#D8BFD8',
'tomato': '#FF6347',
'turquoise': '#40E0D0',
'violet': '#EE82EE',
'wheat': '#F5DEB3',
'white': '#FFFFFF',
'whitesmoke': '#F5F5F5',
'yellow': '#FFFF00',
'yellowgreen': '#9ACD32'
};
var htmlColorKeys = Object.keys(htmlColors);
/**
* Converts a color string to a Color.
*
* @param {*} x - A potential color string.
*
* @returns {*}
*
* @example
* input('#FFFFFF')
*/
var input = function input(x) {
if (typeof x === 'string') {
if (hex(x)) {
return hexToColor(x);
} else if (rgb(x)) {
return rgbToColor(x);
} else if (rgba(x)) {
return rgbaToColor(x);
} else if (html(x)) {
return htmlToColor(x);
}
}
return x;
};
/**
* Converts a Color to a rgba color string.
*
* @param {*} x - A potential Color.
*
* @returns {*}
*
* @example
* output(color)
*/
var output = function output(x) {
if ((typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x.middleware === name) {
return colorToRgba(x);
}
return x;
};
/**
* Is string a hex color?
*
* @param {string} str - A potential hex color.
*
* @returns {boolean}
*
* @example
* hex('#FFFFFF')
*/
var hex = function hex(str) {
return str.match(/^#(?:[0-9a-f]{3}){1,2}$/i) !== null;
};
/**
* Is string a rgba color?
*
* @param {string} str - A potential rgba color.
*
* @returns {boolean}
*
* @example
* rgba('rgba(255,255,255,1)')
*/
var rgba = function rgba(str) {
return str.startsWith('rgba(');
};
/**
* Is string a rgb color?
*
* @param {string} str - A potential rgb color.
*
* @returns {boolean}
*
* @example
* rgb('rgb(255,255,255)')
*/
var rgb = function rgb(str) {
return str.startsWith('rgb(');
};
/**
* Is string a html color?
*
* @param {string} str - A potential html color.
*
* @returns {boolean}
*
* @example
* html('limegreen')
*/
var html = function html(str) {
return htmlColorKeys.indexOf(str) !== -1;
};
/**
* Converts a hex string to a Color.
*
* @param {string} hex - A hex color.
*
* @returns {Color}
*
* @example
* hexToColor('#FFFFFF')
*/
var hexToColor = function hexToColor(hex) {
var x = hex.replace('#', '');
if (x.length === 3) {
var y = '';
for (var i = 0; i < 3; i++) {
var v = x.charAt(i);
y += '' + v + v;
}
x = y;
}
return {
middleware: name,
r: parseInt(x.slice(0, 2), 16),
g: parseInt(x.slice(2, 4), 16),
b: parseInt(x.slice(4, 6), 16),
a: 1
};
};
/**
* Converts a rgb string to a Color.
*
* @param {string} rgb - A rgb color.
*
* @returns {Color}
*
* @example
* rgbToColor('rgb(255,255,255)')
*/
var rgbToColor = function rgbToColor(rgb) {
var x = rgb.replace(/\s/g, '');
var _x$substring$split = x.substring(4, x.length - 1).split(','),
_x$substring$split2 = slicedToArray(_x$substring$split, 3),
r = _x$substring$split2[0],
g = _x$substring$split2[1],
b = _x$substring$split2[2];
return {
middleware: name,
r: parseFloat(r),
g: parseFloat(g),
b: parseFloat(b),
a: 1
};
};
/**
* Converts a rgba string to a Color.
*
* @param {string} rgba - A rgba color.
*
* @returns {Color}
*
* @example
* rgbaToColor('rgba(255,255,255,1)')
*/
var rgbaToColor = function rgbaToColor(rgba) {
var x = rgba.replace(/\s/g, '');
var _x$substring$split3 = x.substring(5, x.length - 1).split(','),
_x$substring$split4 = slicedToArray(_x$substring$split3, 4),
r = _x$substring$split4[0],
g = _x$substring$split4[1],
b = _x$substring$split4[2],
a = _x$substring$split4[3];
return {
middleware: 'color',
r: parseFloat(r),
g: parseFloat(g),
b: parseFloat(b),
a: parseFloat(a)
};
};
/**
* Converts a html string to a Color.
*
* @param {string} html - An html color.
*
* @returns {Color}
*
* @example
* htmlToColor('limegreen')
*/
var htmlToColor = function htmlToColor(html) {
return hexToColor(htmlColors[html]);
};
/**
* Converts a Color to a rgba color string.
*
* @param {Color} color
*
* @returns {string}
*
* @example
* colorToRgba(color)
*/
var colorToRgba = function colorToRgba(_ref) {
var r = _ref.r,
g = _ref.g,
b = _ref.b,
a = _ref.a;
return 'rgba(' + parseInt(limit(r, 0, 255), 10) + ',' + parseInt(limit(g, 0, 255), 10) + ',' + parseInt(limit(b, 0, 255), 10) + ',' + limit(a, 0, 1) + ')';
};
/**
* Find the closest number within limits.
*
* @param {number} num - The desired number.
* @param {number} min - The minimum returned number.
* @param {number} max - the maximum returned number.
*
* @returns {number}
*
* @example
* limit(-1, 2, 5)
*/
var limit = function limit(num, min, max) {
return Math.max(min, Math.min(max, num));
};
var colorMiddleware = { name: name, input: input, output: output };
/**
* A naive, but small, clone function.
*
* @param {*} value
*
* @returns {*}
*
* @example
* clone('hello world')
*/
var clone = function clone(value) {
if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') {
return value;
} else if (Array.isArray(value)) {
var arr = [];
for (var i = 0, l = value.length; i < l; i++) {
arr.push(clone(value[i]));
}
return arr;
} else if (value !== null) {
var obj = {};
for (var key in value) {
obj[key] = clone(value[key]);
}
return obj;
}
return value;
};
/**
* A tweenable unit.
*
* @typedef {Object} Unit
*
* @property {string} middleware - The name of this middleware.
* @property {string} values - The type of color string to output.
*/
var name$1 = 'unit';
var units = ['ch', 'cm', 'em', 'ex', 'in', 'mm', 'pc', 'pt', 'px', 'rem', 'vh', 'vmax', 'vmin', 'vw', '%'];
/**
* Converts a unit string to a Unit.
*
* @param {*} x - A potential unit string.
*
* @returns {*}
*
* @example
* input('20px')
*/
var input$1 = function input(x) {
if (typeof x === 'string') {
var parts = x.split(' ');
var values = [];
for (var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
var number = parseFloat(part);
var unit = part.replace(number, '');
if (!isNaN(number) && (unit === '' || units.indexOf(unit) !== -1)) {
values.push([number, unit]);
} else {
values.push(part);
}
}
if (values.toString() !== parts.toString()) {
return { middleware: name$1, values: values };
}
}
return x;
};
/**
* Converts a Unit to a unit string.
*
* @param {*} x - A potential Unit.
*
* @returns {*}
*
* @example
* output(unit)
*/
var output$1 = function output(x) {
if ((typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'object' && x.middleware === name$1) {
var values = x.values;
var result = [];
for (var i = 0, l = values.length; i < l; i++) {
result.push(values[i].join(''));
}
return result.join(' ');
}
return x;
};
var unitMiddleware = { name: name$1, input: input$1, output: output$1 };
var config = {
defaults: {
keyframe: {
duration: 250,
easing: 'easeInOutQuad'
},
motionPath: {
easing: 'easeInOutQuad'
},
timeline: {
alternate: false,
initialIterations: 0,
iterations: 1,
middleware: [colorMiddleware, unitMiddleware],
queue: 0,
reverse: false
}
}
};
/**
* A group of functions to transform/untransform a value.
*
* @typedef {Object} Middleware
*
* @property {string} name - The name of the middleware.
* @property {function} input - Transform.
* @property {function} output - Untransform.
*/
/**
* Run every part of a value through a function.
*
* @param {*} value
* @param {function} func
*
* @returns {*}
*
* @example
* apply(2, n => n * 2)
*/
var apply$1 = function apply(value, func) {
var v = func(value);
if ((typeof v === 'undefined' ? 'undefined' : _typeof(v)) !== 'object') {
return v;
} else if (Array.isArray(v)) {
var arr = [];
for (var i = 0, l = v.length; i < l; i++) {
arr.push(apply(v[i], func));
}
return arr;
} else if (v !== null) {
var obj = {};
for (var k in v) {
obj[k] = apply(v[k], func);
}
return obj;
}
return v;
};
/**
* Runs each Middleware input function in turn on a value.
*
* @param {*} value
* @param {Middleware[]} middleware
*
* @returns {*}
*
* @example
* input({ foo: 1, bar: [ 2, 3 ] }, middleware)
*/
var input$2 = function input(value, middleware) {
var v = value;
for (var i = 0, l = middleware.length; i < l; i++) {
v = apply$1(v, middleware[i].input);
}
return v;
};
/**
* Runs each Middleware output function in reverse on a value.
*
* @param {*} value
* @param {Middleware[]} middleware
*
* @returns {*}
*
* @example
* output({ foo: 1, bar: [ 2, 3 ] }, middleware)
*/
var output$2 = function output(value, middleware) {
var v = value;
for (var i = middleware.length - 1; i >= 0; i--) {
v = apply$1(v, middleware[i].output);
}
return v;
};
/* globals true */
/**
* The position of an object on a Timeline
* where 0 is Timeline start and 1 is Timeline finish.
*
* @typedef {Object} TimelinePosition
*
* @property {Position} start
* @property {Position} finish
*/
/**
* A Shape positioned on a Timeline.
*
* @typedef {Object} TimelineShape
*
* @property {Shape} shape
* @property {TimelinePosition} timelinePosition
*/
/**
* The position of an object on a Timeline in milliseconds.
*
* @typedef {Object} MsTimelinePosition
*
* @property {number} start.
* @property {number} finish.
*/
/**
* A Shape positioned on a Timeline (position set in milliseconds).
*
* @typedef {Object} MsTimelineShape
*
* @property {Shape} shape
* @property {MsTimelinePosition} timelinePosition
*/
/**
* A TimelineShape array and their total duration.
*
* @typedef {Object} TimelineShapesAndDuration
*
* @property {TimelineShape[]} timelineShapes
* @property {number} duration
*/
/**
* The options required to calculate the current playback Position.
*
* @typedef {Object} PlaybackOptions
*
* @property {boolean} alternate - Should the next iteration reverse current direction?
* @property {number} duration - Milliseconds that each iteration lasts.
* @property {number} initialIterations - The starting number of iterations.
* @property {number} iterations - The number of playback interations (additional to initialIterations).
* @property {boolean} reverse - Should the first iteration start in a reverse direction?
* @property {number} [started] - The UNIX timestamp of playback start.
*/
/**
* PlaybackOptions and tween middleware.
*
* @typedef {Object} TimelineOptions
*
* @extends PlaybackOptions
* @property {Middleware[]} middleware
*/
/**
* A Shape and timeline related options.
*
* @typedef {Object} ShapeWithOptions
*
* @property {(string|number)} [after] - The name of the Shape to queue after (in sequence).
* @property {(string|number)} [at] - The name of the Shape to queue at (in parallel).
* @property {(string|number)} name - A unique reference.
* @property {number} offset - The offset in milliseconds to adjust the queuing of this shape.
* @property {Shape} shape
*/
/**
* An object containing Middlware, PlaybackOptions and ShapesWithOptions.
*
* @typedef {Object} SortedTimelineProps
*
* @property {Middleware[]} middleware
* @property {PlaybackOptions} playbackOptions
* @property {ShapeWithOptions[]} shapesWithOptions
*/
/**
* A sequence of Shapes.
*
* @typedef {Object} Timeline
*
* @property {Middleware[]} middleware
* @property {PlaybackOptions} playbackOptions
* @property {Object} state - Holds the last known state of the timeline.
* @property {TimelineShape[]} timelineShapes
*/
/**
* Runs each Middleware input function on every Keyframe's FrameShape.
*
* @param {Shape} shape
* @param {Middleware[]} middleware
*
* @example
* apply(shape, middleware)
*/
var apply = function apply(_ref, middleware) {
var keyframes = _ref.keyframes;
for (var i = 0, l = keyframes.length; i < l; i++) {
var keyframe = keyframes[i];
keyframe.frameShape = input$2(keyframe.frameShape, middleware);
}
};
/**
* Is playback currently in reverse?
*
* @param {PlaybackOptions} playbackOptions
* @param {number} complete - The number of iterations complete.
*
* @example
* currentReverse(playbackOptions, complete)
*/
var currentReverse = function currentReverse(playbackOptions, complete) {
var reverse = playbackOptions.reverse;
if (complete === 0) {
return reverse;
}
var alternate = playbackOptions.alternate;
var initialIterations = playbackOptions.initialIterations;
var initialReverse = sameDirection(alternate, initialIterations) ? reverse : !reverse;
return sameDirection(alternate, initialIterations + complete) ? initialReverse : !initialReverse;
};
/**
* The number of iterations a Timeline has completed.
*
* @param {PlaybackOptions} playbackOptions
* @param {number} opts.at
*
* @returns {number}
*
* @example
* iterationsComplete(playbackOptions, 1000)
*/
var iterationsComplete = function iterationsComplete(playbackOptions, at) {
var duration = playbackOptions.duration;
var iterations = playbackOptions.iterations;
var started = playbackOptions.started;
if (typeof started === 'undefined' || at <= started) {
return 0;
}
var ms = at - started;
var maxDuration = duration * iterations;
if (ms >= maxDuration) {
return iterations;
}
return ms / duration;
};
/**
* Stops playback of a Timeline.
*
* @param {Timeline} timeline
* @param {PlaybackOptions} playbackOptions
* @param {number} [at]
*
* @example
* pause(timeline)
*/
var pause = function pause(timeline) {
var playbackOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var at = arguments[2];
timeline.playbackOptions = updatePlaybackOptions({ at: at, timeline: timeline, pause: true, playbackOptions: playbackOptions });
updateState(timeline, at);
};
/**
* Starts playback of a Timeline.
*
* @param {Timeline} timeline
* @param {PlaybackOptions} playbackOptions
* @param {number} [at]
*
* @example
* play(timeline, { initialIterations: 0 })
*/
var play = function play(timeline) {
var playbackOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var at = arguments[2];
timeline.playbackOptions = updatePlaybackOptions({ at: at, timeline: timeline, playbackOptions: playbackOptions });
updateState(timeline, at);
};
/**
* Calculate the Timeline Position.
*
* @param {number} totalIterations - initialIterations + iterationsComplete.
* @param {boolean} reverse - Is the Timeline currently in reverse?
*
* @returns {Position}
*
* @example
* position(5.43, true)
*/
var position = function position(totalIterations, reverse) {
var i = totalIterations >= 1 && totalIterations % 1 === 0 ? 1 : totalIterations % 1;
return reverse ? 1 - i : i;
};
/**
* Is the direction same as initial direction?
*
* @param {boolean} alternate - Is iteration direction alternating?
* @param {number} iterations - The number of iterations complete.
*
* @return {boolean}
*
* @example
* sameDirection(true, 3.25)
*/
var sameDirection = function sameDirection(alternate, iterations) {
var x = iterations % 2;
return !alternate || iterations === 0 || x <= 1 && x % 2 > 0;
};
/**
* Calculate the start position of a Shape on the Timeline.
*
* @param {Object} props
* @param {(string|number)} [props.after]
* @param {(string|number)} [props.at]
* @param {MsTimelineShape[]} props.msTimelineShapes
* @param {number} props.offset
* @param {number} props.timelineFinish - The current finish of the timeline.
*
* @returns {number}
*
* @example
* shapeStart({ 'foo', msTimelineShapes, 200, 2000 })
*/
var shapeStart = function shapeStart(_ref2) {
var after = _ref2.after,
at = _ref2.at,
msTimelineShapes = _ref2.msTimelineShapes,
offset = _ref2.offset,
timelineFinish = _ref2.timelineFinish;
if (typeof after !== 'undefined' || typeof at !== 'undefined') {
var reference = typeof after !== 'undefined' ? after : at;
for (var i = 0; i < msTimelineShapes.length; i++) {
var s = msTimelineShapes[i];
if (reference === s.shape.name) {
return (typeof at !== 'undefined' ? s.timelinePosition.start : s.timelinePosition.finish) + offset;
}
}
for (var _i = 0; _i < msTimelineShapes.length; _i++) {
var _s = msTimelineShapes[_i];
for (var j = 0; j < _s.shape.keyframes.length; j++) {
var keyframe = _s.shape.keyframes[j];
if (reference === keyframe.name) {
return _s.timelinePosition.start + _s.shape.duration * keyframe.position + offset;
}
}
}
{
throw new Error('No Shape or Keyframe matching name \'' + reference + '\'');
}
}
return timelineFinish + offset;
};
/**
* Create a ShapeWithOptions from an array.
*
* @param {Object[]} arr
* @param {Shape} arr.0
* @param {Object} arr.1
*
* @returns {ShapeWithOptions}
*
* @example
* shapeWithOptionsFromArray(arr, i)
*/
var shapeWithOptionsFromArray = function shapeWithOptionsFromArray(_ref3, i) {
var _ref4 = slicedToArray(_ref3, 2),
shape = _ref4[0],
options = _ref4[1];
if (true && ((typeof shape === 'undefined' ? 'undefined' : _typeof(shape)) !== 'object' || !shape.keyframes)) {
throw new TypeError('When an array is passed to the timeline function the first item must be a Shape');
}
if (true && (typeof options === 'undefined' ? 'undefined' : _typeof(options)) !== 'object') {
throw new TypeError('When an array is passed to the timeline function the second item must be an object');
}
var _options$name = options.name,
name = _options$name === undefined ? i : _options$name,
_options$queue = options.queue,
queue = _options$queue === undefined ? config.defaults.timeline.queue : _options$queue;
if (true && typeof name !== 'string' && typeof name !== 'number') {
throw new TypeError('The name prop must be of type string or number');
}
if ((typeof queue === 'undefined' ? 'undefined' : _typeof(queue)) === 'object' && !Array.isArray(queue) && queue !== null) {
var after = queue.after,
at = queue.at,
_queue$offset = queue.offset,
offset = _queue$offset === undefined ? 0 : _queue$offset;
if (true && typeof offset !== 'undefined' && typeof offset !== 'number') {
throw new TypeError('The queue.offset prop must be of type number');
}
if (true && typeof at !== 'undefined' && typeof after !== 'undefined') {
throw new TypeError('You cannot pass both queue.at and queue.after props');
}
if (true && typeof at !== 'undefined' && typeof at !== 'string' && typeof at !== 'number') {
throw new TypeError('The queue.at prop must be of type string or number');
}
if (true && typeof after !== 'undefined' && typeof after !== 'string' && typeof after !== 'number') {
throw new TypeError('The queue.after prop must be of type string or number');
}
if (typeof at !== 'undefined') {
return { at: at, name: name, offset: offset, shape: shape };
}
if (typeof after !== 'undefined') {
return { after: after, name: name, offset: offset, shape: shape };
}
return { name: name, offset: offset, shape: shape };
} else if (typeof queue === 'number') {
return { name: name, offset: queue, shape: shape };
} else if (typeof queue === 'string') {
return { after: queue, name: name, offset: 0, shape: shape };
}
{
throw new TypeError('The queue prop must be of type number, string or object');
}
return { name: name, offset: 0, shape: shape };
};
/**
* Sorts an array of Shapes, ShapesWithOptions and TimelineOptions.
*
* @param {(Shape|Object[]|TimelineOptions)[]} props
*
* @returns {SortedTimelineProps}
*
* @example
* sort(props)
*/
var sort = function sort(props) {
if (true && props.length === 0) {
throw new TypeError('The timeline function must be passed at least one Shape');
}
var options = {};
var shapesWithOptions = [];
for (var i = 0, l = props.length; i < l; i++) {
var prop = props[i];
if (Array.isArray(prop)) {
shapesWithOptions.push(shapeWithOptionsFromArray(prop, i));
} else {
if (true && (typeof prop === 'undefined' ? 'undefined' : _typeof(prop)) !== 'object') {
throw new TypeError('The timeline function must only be passed objects and arrays');
}
if (prop.keyframes) {
shapesWithOptions.push({
name: i,
offset: config.defaults.timeline.queue,
shape: prop
});
} else {
{
if (i === 0) {
throw new TypeError('The timeline function must receive a Shape as the first argument');
} else if (i !== props.length - 1) {
throw new TypeError('The timeline function must receive options as the final argument');
}
}
options = clone(prop);
}
}
}
return {
middleware: validMiddleware(options),
playbackOptions: validPlaybackOptions(options),
shapesWithOptions: shapesWithOptions
};
};
/**
* Creates a Timeline from one or more Shape.
* Optionally can take an options object as the last argument,
* as well as options for each Shape if passed in as an array.
*
* @param {...(Shape|Object[]|TimelineOptions)} props
*
* @returns {Timeline}
*
* @example
* timeline(circle, [ square, { queue: -200 } ], { duration: 5000 })
*/
var timeline = function timeline() {
for (var _len = arguments.length, props = Array(_len), _key = 0; _key < _len; _key++) {
props[_key] = arguments[_key];
}
var _sort = sort(props),
middleware = _sort.middleware,
playbackOptions = _sort.playbackOptions,
shapesWithOptions = _sort.shapesWithOptions;
var _timelineShapesAndDur = timelineShapesAndDuration(shapesWithOptions, middleware),
duration = _timelineShapesAndDur.duration,
timelineShapes = _timelineShapesAndDur.timelineShapes;
if (typeof playbackOptions.duration === 'undefined') {
playbackOptions.duration = duration;
}
var t = { middleware: middleware, playbackOptions: playbackOptions, state: {}, timelineShapes: timelineShapes };
for (var i = 0, l = timelineShapes.length; i < l; i++) {
var shape = timelineShapes[i].shape;
shape.timeline = t;
shape.timelineIndex = i;
}
updateState(t);
t.event = event(t);
return t;
};
/**
* Converts a set of MsTimelineShapes to a set of TimelineShapes
* given the Timeline start and total duration values.
*
* @param {Object} props
* @param {number} props.duration
* @param {msTimelineShape[]} props.msTimelineShapes
* @param {number} props.start
*
* @returns {TimelineShape[]}
*
* @example
* timelineShapes()
*/
var timelineShapes = function timelineShapes(_ref5) {
var duration = _ref5.duration,
msTimelineShapes = _ref5.msTimelineShapes,
start = _ref5.start;
var s = [];
for (var i = 0, l = msTimelineShapes.length; i < l; i++) {
var msTimelineShape = msTimelineShapes[i];
var timelinePosition = msTimelineShape.timelinePosition;
s.push({
shape: msTimelineShape.shape,
timelinePosition: {
start: (timelinePosition.start - start) / duration,
finish: (timelinePosition.finish - start) / duration
}
});
}
return s;
};
/**
* Converts an array of ShapesWithOptions into TimelineShapes
* and their total duration.
*
* @param {ShapeWithOptions[]} shapesWithOptions
* @param {Middleware[]} middleware
*
* @returns {TimelineShapesAndDuration}
*
* @example
* timelineShapes(shapesWithOptions)
*/
var timelineShapesAndDuration = function timelineShapesAndDuration(shapesWithOptions, middleware) {
var timelineStart = 0;
var timelineFinish = 0;
var msTimelineShapes = [];
for (var i = 0, l = shapesWithOptions.length; i < l; i++) {
var _shapesWithOptions$i = shapesWithOptions[i],
after = _shapesWithOptions$i.after,
at = _shapesWithOptions$i.at,
name = _shapesWithOptions$i.name,
offset = _shapesWithOptions$i.offset,
shape = _shapesWithOptions$i.shape;
if (true && typeof shape.timeline !== 'undefined') {
throw new Error('A Shape can only be added to one timeline');
}
shape.name = name;
apply(shape, middleware);
var start = shapeStart({
after: after,
at: at,
msTimelineShapes: msTimelineShapes,
offset: offset,
timelineFinish: timelineFinish
});
var finish = start + shape.duration;
timelineStart = Math.min(timelineStart, start);
timelineFinish = Math.max(timelineFinish, finish);
msTimelineShapes.push({ shape: shape, timelinePosition: { start: start, finish: finish } });
}
var timelineDuration = Math.abs(timelineStart - timelineFinish);
return {
duration: timelineDuration,
timelineShapes: timelineShapes({
duration: timelineDuration,
msTimelineShapes: msTimelineShapes,
start: timelineStart
})
};
};
/**
* Updates the PlaybackOptions of a Timeline.
*
* @param {Object} opts
* @param {number} [opts.at]
* @param {PlaybackOptions} opts.playbackOptions
* @param {Timeline} opts.timeline
*
* @example
* updatePlaybackOptions({ timeline, playbackOptions })
*/
var updatePlaybackOptions = function updatePlaybackOptions(_ref6) {
var at = _ref6.at,
_ref6$pause = _ref6.pause,
pause = _ref6$pause === undefined ? false : _ref6$pause,
playbackOptions = _ref6.playbackOptions,
timeline = _ref6.timeline;
if (true && ((typeof timeline === 'undefined' ? 'undefined' : _typeof(timeline)) !== 'object' || !timeline.timelineShapes || !timeline.playbackOptions)) {
throw new TypeError('The updatePlaybackOptions function must be passed a Timeline');
}
if (true && typeof at !== 'undefined' && typeof at !== 'number') {
throw new TypeError('The updatePlaybackOptions function at property must be of type number');
}
var previous = timeline.playbackOptions;
var next = validPlaybackOptions(_extends({}, previous, playbackOptions, {
started: typeof at !== 'undefined' ? at : Date.now()
}));
if (typeof playbackOptions.initialIterations !== 'undefined') {
if (typeof playbackOptions.reverse === 'undefined') {
next.reverse = currentReverse(previous, next.initialIterations - previous.initialIterations);
}
if (typeof playbackOptions.iterations === 'undefined' && previous.iterations !== Infinity) {
next.iterations = Math.max(0, previous.initialIterations + previous.iterations - next.initialIterations);
}
} else {
var complete = iterationsComplete(previous, next.started);
var reverse = currentReverse(previous, complete);
next.initialIterations = previous.initialIterations + complete;
if (typeof playbackOptions.iterations === 'undefined') {
next.iterations = previous.iterations - complete;
if (typeof playbackOptions.reverse !== 'undefined' && next.reverse !== previous.reverse && next.iterations !== Infinity) {
var nextIterations = next.initialIterations;
next.initialIterations = next.iterations;
next.iterations = nextIterations;
}
} else {
if (typeof playbackOptions.reverse !== 'undefined' && playbackOptions.reverse !== reverse && next.iterations !== Infinity) {
next.initialIterations = previous.iterations - complete;
}
}
if (typeof playbackOptions.reverse === 'undefined') {
next.reverse = reverse;
} else if (next.iterations === Infinity) {
next.initialIterations = playbackOptions.reverse === reverse ? next.initialIterations % 1 : 1 - next.initialIterations % 1;
}
}
if (pause) {
delete next.started;
}
return next;
};
/**
* Updates the Timeline state.
*
* @param {Timeline} timeline
* @param {number} at
*
* @example
* updateState(timeline, Date.now())
*/
var updateState = function updateState(t, at) {
var playbackOptions = t.playbackOptions;
var state = t.state;
state.started = typeof playbackOptions.started !== 'undefined';
state.iterationsComplete = iterationsComplete(playbackOptions, at);
state.totalIterations = playbackOptions.initialIterations + state.iterationsComplete;
state.reverse = currentReverse(playbackOptions, state.iterationsComplete);
state.finished = playbackOptions.iterations - state.iterationsComplete === 0;
state.position = position(state.totalIterations, state.reverse);
};
/**
* Extracts and validates Middlware from an object.
*
* @param {Object} opts
*
* @returns {Middleware[]}
*
* @example
* validMiddleware(opts)
*/
var validMiddleware = function validMiddleware(_ref7) {
var _ref7$middleware = _ref7.middleware,
middleware = _ref7$middleware === undefined ? config.defaults.timeline.middleware : _ref7$middleware;
if (!Array.isArray(middleware)) {
throw new TypeError('The timeline function middleware option must be of type array');
}
for (var i = 0, l = middleware.length; i < l; i++) {
var _middleware$i = middleware[i],
name = _middleware$i.name,
_input = _middleware$i.input,
output = _middleware$i.output;
if (typeof name !== 'string') {
throw new TypeError('A middleware must have a name prop');
}
if (typeof _input !== 'function') {
throw new TypeError('The ' + name + ' middleware must have an input method');
}
if (typeof output !== 'function') {
throw new TypeError('The ' + name + ' middleware must have an output method');
}
}
return middleware;
};
/**
* Extracts and validates PlaybackOptions from an object.
*
* @param {Object} opts
*
* @returns {PlaybackOptions}
*
* @example
* validPlaybackOptions(opts)
*/
var validPlaybackOptions = function validPlaybackOptions(_ref8) {
var _ref8$alternate = _ref8.alternate,
alternate = _ref8$alternate === undefined ? config.defaults.timeline.alternate : _ref8$alternate,
duration = _ref8.duration,
_ref8$initialIteratio = _ref8.initialIterations,
initialIterations = _ref8$initialIteratio === undefined ? config.defaults.timeline.initialIterations : _ref8$initialIteratio,
_ref8$iterations = _ref8.iterations,
iterations = _ref8$iterations === undefined ? config.defaults.timeline.iterations : _ref8$iterations,
_ref8$reverse = _ref8.reverse,
reverse = _ref8$reverse === undefined ? config.defaults.timeline.reverse : _ref8$reverse,
started = _ref8.started;
var playbackOptions = {};
if (typeof duration !== 'undefined') {
if (true && (typeof duration !== 'number' || duration < 0)) {
throw new TypeError('The timeline function duration option must be a positive number or zero');
}
playbackOptions.duration = duration;
}
{
if (typeof alternate !== 'boolean') {
throw new TypeError('The timeline function alternate option must be true or false');
}
if (typeof initialIterations !== 'number' || initialIterations < 0) {
throw new TypeError('The timeline function initialIterations option must be a positive number or zero');
}
if (typeof iterations !== 'number' || iterations < 0) {
throw new TypeError('The timeline function iterations option must be a positive number or zero');
}
if (typeof reverse !== 'boolean') {
throw new TypeError('The timeline function reverse option must be true or false');
}
}
if (typeof started !== 'undefined') {
if (true && (typeof started !== 'number' || started < 0)) {
throw new TypeError('The timeline function started option must be a positive number or zero');
}
playbackOptions.started = started;
}
return _extends({}, playbackOptions, {
alternate: alternate,
initialIterations: initialIterations,
iterations: iterations,
reverse: reverse
});
};
/* globals true */
/**
* An event.
*
* @typedef {Object} Event
*
* @property {number} at - The time the event occured.
* @property {string} name - The event name.
* @property {Object} options - Any additional event data.
*/
/**
* A Timeline event subscription.
*
* @typedef {Object} EventSubscription
*
* @property {function} callback
* @property {string} name
* @property {number} token
*/
/**
* An object to hold Timeline EventSubscriptions, and subscribe/unsubscribe functions.
*
* @typedef {Object} EventObject
*
* @property {Object} previousPlaybackOptions
* @property {Object} previousState
* @property {function} subscribe - A function to subscribe to Timeline events.
* @property {EventSubscription[]} subscriptions
* @property {function} unsubscribe - A function to unsubscribe to Timeline events.
*/
/**
* Token incrementor.
*/
var t = 0;
/**
* Accepted event names.
*/
var acceptedEventNames = ['timeline.start', 'timeline.finish', 'shape.start', 'shape.finish', 'keyframe', 'frame'];
/**
* An EventObject creator.
*
* @param {Timeline} timeline
*
* @returns {EventObject}
*
* @example
* event(timeline)
*/
var event = function event(timeline) {
return {
previousPlaybackOptions: {},
previousState: {},
subscribe: subscribe(timeline),
subscriptions: [],
unsubscribe: unsubscribe(timeline)
};
};
/**
* Is a Timeline active?
*
* @param {Timeline} timeline
*
* @returns {boolean}
*
* @example
* active(timeline)
*/
var active = function active(_ref) {
var event = _ref.event,
state = _ref.state;
return state.started && (!state.finished || typeof event.previousState === 'undefined' || !event.previousState.finished);
};
/**
* A unique list of Timeline EventSubscription names.
*
* @param {Timeline} timeline
*
* @returns {string[]}
*
* @example
* activeEventNames(timeline)
*/
var activeEventNames = function activeEventNames(_ref2) {
var subscriptions = _ref2.event.subscriptions;
var s = [];
for (var i = 0, l = subscriptions.length; i < l; i++) {
var name = subscriptions[i].name;
if (s.indexOf(name) === -1) {
s.push(name);
}
}
return s;
};
/**
* Run EventSubscription callbacks for every event that has occured since last check.
*
* @param {Timeline} timeline
*
* @example
* events(timeline)
*/
var events = function events(timeline) {
if (playbackOptionsChanged(timeline)) {
timeline.event.previousPlaybackOptions = {};
timeline.event.previousState = {};
}
var subscriptions = timeline.event.subscriptions;
if (subscriptions.length && active(timeline)) {
var eventNames = activeEventNames(timeline);
var queue = eventQueue(timeline, eventNames);
for (var i = 0, l = queue.length; i < l; i++) {
var _event = queue[i];
var eventName = _event.name;
var options = _event.options || {};
for (var _i = 0, _l = subscriptions.length; _i < _l; _i++) {
var subscription = subscriptions[_i];
if (eventName === subscription.name) {
subscription.callback(options);
}
}
}
}
timeline.event.previousPlaybackOptions = _extends({}, timeline.playbackOptions);
timeline.event.previousState = _extends({}, timeline.state);
};
/**
* An array of Events that have occured since last checked.
*
* @param {Timeline} timeline
* @param {string[]} eventNames
*
* @returns {Event[]}
*
* @example
* eventQueue(timeline, eventNames)
*/
var eventQueue = function eventQueue(_ref3, eventNames) {
var previousState = _ref3.event.previousState,
playbackOptions = _ref3.playbackOptions,
state = _ref3.state,
timelineShapes = _ref3.timelineShapes;
var queue = [];
var alternate = playbackOptions.alternate,
duration = playbackOptions.duration,
initialIterations = playbackOptions.initialIterations,
iterations = playbackOptions.iterations,
reverse = playbackOptions.reverse,
started = playbackOptions.started;
var max = started + duration * state.iterationsComplete;
var min = typeof previousState.iterationsComplete !== 'undefined' ? started + duration * previousState.iterationsComplete + 1 : 0;
var getTimestamps = function getTimestamps(pos) {
return positionTimestamps({
alternate: alternate,
duration: duration,
initialIterations: initialIterations,
iterations: iterations,
max: max,
min: min,
position: pos,
reverse: reverse,
started: started
});
};
if (eventNames.indexOf('timeline.start') !== -1) {
var timestamps = getTimestamps(0);
for (var i = 0, l = timestamps.length; i < l; i++) {
queue.push({ name: 'timeline.start', at: timestamps[i] });
}
}
if (eventNames.indexOf('timeline.finish') !== -1) {
var _timestamps = getTimestamps(1);
for (var _i2 = 0, _l2 = _timestamps.length; _i2 < _l2; _i2++) {
queue.push({ name: 'timeline.finish', at: _timestamps[_i2] });
}
}
if (eventNames.indexOf('shape.start') !== -1) {
for (var _i3 = 0, _l3 = timelineShapes.length; _i3 < _l3; _i3++) {
var _timelineShapes$_i = timelineShapes[_i3],
shapeName = _timelineShapes$_i.shape.name,
start = _timelineShapes$_i.timelinePosition.start;
var _timestamps2 = getTimestamps(start);
for (var _i = 0, _l = _timestamps2.length; _i < _l; _i++) {
queue.push({ name: 'shape.start', at: _timestamps2[_i], options: { shapeName: shapeName } });
}
}
}
if (eventNames.indexOf('shape.finish') !== -1) {
for (var _i4 = 0, _l4 = timelineShapes.length; _i4 < _l4; _i4++) {
var _timelineShapes$_i2 = timelineShapes[_i4],
shapeName = _timelineShapes$_i2.shape.name,
finish = _timelineShapes$_i2.timelinePosition.finish;
var _timestamps3 = getTimestamps(finish);
for (var _i5 = 0, _l5 = _timestamps3.length; _i5 < _l5; _i5++) {
queue.push({ name: 'shape.finish', at: _timestamps3[_i5], options: { shapeName: shapeName } });
}
}
}
if (eventNames.indexOf('keyframe') !== -1) {
for (var _i6 = 0, _l6 = timelineShapes.length; _i6 < _l6; _i6++) {
var _timelineShapes$_i3 = timelineShapes[_i6],
_timelineShapes$_i3$s = _timelineShapes$_i3.shape,
shapeName = _timelineShapes$_i3$s.name,
keyframes = _timelineShapes$_i3$s.keyframes,
_timelineShapes$_i3$t = _timelineShapes$_i3.timelinePosition,
start = _timelineShapes$_i3$t.start,
finish = _timelineShapes$_i3$t.finish;
for (var _i7 = 0, _l7 = keyframes.length; _i7 < _l7; _i7++) {
var _keyframes$_i = keyframes[_i7],
keyframeName = _keyframes$_i.name,
position$$1 = _keyframes$_i.position;
var keyframePosition = start + (finish - start) * position$$1;
var _timestamps4 = getTimestamps(keyframePosition);
for (var __i = 0, __l = _timestamps4.length; __i < __l; __i++) {
queue.push({ name: 'keyframe', at: _timestamps4[__i], options: { keyframeName: keyframeName, shapeName: shapeName } });
}
}
}
}
if (eventNames.indexOf('frame') !== -1) {
queue.push({ name: 'frame', at: max });
}
return queue.sort(oldest);
};
/**
* A sort function for Events.
*
* @param {Event} a
* @param {Event} b
*
* @returns {number}
*
* @example
* oldest(event1, event2)
*/
var oldest = function oldest(a, b) {
return a.at === b.at ? 0 : a.at < b.at ? -1 : 1;
};
/**
* Have playbackOptions changed since last check?
*
* @param {Timeline} timeline
*
* @return {boolean}
*
* @example
* playbackOptionsChanged(timeline)
*/
var playbackOptionsChanged = function playbackOptionsChanged(timeline) {
return JSON.stringify(timeline.playbackOptions) !== JSON.stringify(timeline.event.previousPlaybackOptions);
};
/**
* Timestamps at which a Timeline was at a Position.
*
* @param {Object} opts
* @param {boolean} opts.alternate
* @param {number} opts.duration
* @param {number} initialIterations
* @param {number} iterations
* @param {number} opts.max - The maximum bound within which to look for timestamps.
* @param {number} opts.min - The minimum bound within which to look for timestamps.
* @param {Position} opts.position - The Position in question.
* @param {boolean} opts.reverse
* @param {number} opts.started
*
* @returns {number[]}
*
* @example
* positionTimestamps(opts)
*/
var positionTimestamps = function positionTimestamps(_ref4) {
var alternate = _ref4.alternate,
duration = _ref4.duration,
initialIterations = _ref4.initialIterations,
iterations = _ref4.iterations,
max = _ref4.max,
min = _ref4.min,
position$$1 = _ref4.position,
reverse = _ref4.reverse,
started = _ref4.started;
var startedPosition = position(initialIterations, reverse);
var finishedTimestamp = started + duration * iterations;
var timestamps = function timestamps(timestamp) {
if (timestamp <= max) {
var timestampReverse = currentReverse({
alternate: alternate,
initialIterations: initialIterations,
iterations: iterations,
reverse: reverse
}, iterationsComplete({ duration: duration, iterations: iterations, started: started }, timestamp));
var positionAtEnd = position$$1 === 0 || position$$1 === 1;
var timelineFinished = timestamp === finishedTimestamp;
var finishedAtPosition = position$$1 === 0 && timestampReverse || position$$1 === 1 && !timestampReverse;
if (timestamp <= finishedTimestamp && (!positionAtEnd || !timelineFinished || finishedAtPosition)) {
var _t = timestamp >= min ? [timestamp] : [];
return _t.concat(timestamps(timestamp + timeToSamePosition({
alternate: alternate,
duration: duration,
position: position$$1,
reverse: timestampReverse
})));
}
}
return [];
};
return timestamps(started + timeToPosition({
alternate: alternate,
duration: duration,
from: startedPosition,
reverse: reverse,
to: position$$1
}));
};
/**
* The number of milliseconds between two Positions during Timeline playback.
*
* @param {Object} opts
* @param {boolean} opts.alternate
* @param {number} opts.duration
* @param {Position} opts.from - The from Position.
* @param {boolean} opts.reverse - Is Timeline in reverse at the from Position?
* @param {Position} opts.to - The to Position.
*
* @returns {number}
*
* @example
* timeToPosition(opts)
*/
var timeToPosition = function timeToPosition(_ref5) {
var alternate = _ref5.alternate,
duration = _ref5.duration,
from = _ref5.from,
reverse = _ref5.reverse,
to = _ref5.to;
return duration * (alternate ? reverse ? from < to ? to + from : from - to : from > to ? 2 - (to + from) : to - from : reverse ? from === 1 && to === 0 ? 1 : (1 - to + from) % 1 : from === 0 && to === 1 ? 1 : (1 - from + to) % 1);
};
/**
* The number of milliseconds between the same Position during Timeline playback.
*
* @param {Object} opts
* @param {boolean} opts.alternate
* @param {number} opts.duration
* @param {Position} opts.position
* @param {boolean} opts.reverse - Is Timeline in reverse at the Position?
*
* @returns {number}
*
* @example
* timeToSamePosition(opts)
*/
var timeToSamePosition = function timeToSamePosition(_ref6) {
var alternate = _ref6.alternate,
duration = _ref6.duration,
position$$1 = _ref6.position,
reverse = _ref6.reverse;
return duration * (alternate ? reverse ? (position$$1 === 0 ? 1 : position$$1) * 2 : 2 - (position$$1 === 1 ? 0 : position$$1) * 2 : 1);
};
/**
* Creates a sub