Skip to content
{{ message }}

Instantly share code, notes, and snippets.

trusktr/infamous.a735f17.js

Created Dec 17, 2017
 var infamous = (function (exports) { 'use strict'; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: mark@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /** * A high-performance static matrix math library used to calculate * affine transforms on surfaces and other renderables. * Famo.us uses 4x4 matrices corresponding directly to * WebKit matrices (column-major order). * * The internal "type" of a Matrix is a 16-long float array in * row-major order, with: * elements [0],[1],[2],[4],[5],[6],[8],[9],[10] forming the 3x3 * transformation matrix; * elements [12], [13], [14] corresponding to the t_x, t_y, t_z * translation; * elements [3], [7], [11] set to 0; * element [15] set to 1. * All methods are static. * * @static * * @class Transform */ var Transform = {}; // WARNING: these matrices correspond to WebKit matrices, which are // transposed from their math counterparts Transform.precision = 1e-6; Transform.identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; /** * Multiply two or more Transform matrix types to return a Transform matrix. * * @method multiply4x4 * @static * @param {Transform} a left Transform * @param {Transform} b right Transform * @return {Transform} */ Transform.multiply4x4 = function multiply4x4(a, b) { return [ a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3], a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3], a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3], a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3], a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7], a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7], a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7], a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7], a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11], a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11], a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11], a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11], a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15], a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15], a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15], a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15] ]; }; /** * Fast-multiply two Transform matrix types to return a * Matrix, assuming bottom row on each is [0 0 0 1]. * * @method multiply * @static * @param {Transform} a left Transform * @param {Transform} b right Transform * @return {Transform} */ Transform.multiply = function multiply(a, b) { return [ a[0] * b[0] + a[4] * b[1] + a[8] * b[2], a[1] * b[0] + a[5] * b[1] + a[9] * b[2], a[2] * b[0] + a[6] * b[1] + a[10] * b[2], 0, a[0] * b[4] + a[4] * b[5] + a[8] * b[6], a[1] * b[4] + a[5] * b[5] + a[9] * b[6], a[2] * b[4] + a[6] * b[5] + a[10] * b[6], 0, a[0] * b[8] + a[4] * b[9] + a[8] * b[10], a[1] * b[8] + a[5] * b[9] + a[9] * b[10], a[2] * b[8] + a[6] * b[9] + a[10] * b[10], 0, a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12], a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13], a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14], 1 ]; }; /** * Return a Transform translated by additional amounts in each * dimension. This is equivalent to the result of * * Transform.multiply(Matrix.translate(t[0], t[1], t[2]), m). * * @method thenMove * @static * @param {Transform} m a Transform * @param {Array.Number} t floats delta vector of length 2 or 3 * @return {Transform} */ Transform.thenMove = function thenMove(m, t) { if (!t[2]) { t[2] = 0; } return [m[0], m[1], m[2], 0, m[4], m[5], m[6], 0, m[8], m[9], m[10], 0, m[12] + t[0], m[13] + t[1], m[14] + t[2], 1]; }; /** * Return a Transform matrix which represents the result of a transform matrix * applied after a move. This is faster than the equivalent multiply. * This is equivalent to the result of: * * Transform.multiply(m, Transform.translate(t[0], t[1], t[2])). * * @method moveThen * @static * @param {Array.Number} v vector representing initial movement * @param {Transform} m matrix to apply afterwards * @return {Transform} the resulting matrix */ Transform.moveThen = function moveThen(v, m) { if (!v[2]) { v[2] = 0; } var t0 = v[0] * m[0] + v[1] * m[4] + v[2] * m[8]; var t1 = v[0] * m[1] + v[1] * m[5] + v[2] * m[9]; var t2 = v[0] * m[2] + v[1] * m[6] + v[2] * m[10]; return Transform.thenMove(m, [t0, t1, t2]); }; /** * Return a Transform which represents a translation by specified * amounts in each dimension. * * @method translate * @static * @param {Number} x x translation * @param {Number} y y translation * @param {Number} z z translation * @return {Transform} */ Transform.translate = function translate(x, y, z) { if (z === undefined) { z = 0; } return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1]; }; /** * Return a Transform scaled by a vector in each * dimension. This is a more performant equivalent to the result of * * Transform.multiply(Transform.scale(s[0], s[1], s[2]), m). * * @method thenScale * @static * @param {Transform} m a matrix * @param {Array.Number} s delta vector (array of floats && * array.length == 3) * @return {Transform} */ Transform.thenScale = function thenScale(m, s) { return [ s[0] * m[0], s[1] * m[1], s[2] * m[2], 0, s[0] * m[4], s[1] * m[5], s[2] * m[6], 0, s[0] * m[8], s[1] * m[9], s[2] * m[10], 0, s[0] * m[12], s[1] * m[13], s[2] * m[14], 1 ]; }; /** * Return a Transform which represents a scale by specified amounts * in each dimension. * * @method scale * @static * @param {Number} x x scale factor * @param {Number} y y scale factor * @param {Number} z z scale factor * @return {Transform} */ Transform.scale = function scale(x, y, z) { if (z === undefined) { z = 1; } if (y === undefined) { y = x; } return [x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1]; }; /** * Return a Transform which represents a clockwise * rotation around the x axis. * * @method rotateX * @static * @param {Number} theta radians * @return {Transform} */ Transform.rotateX = function rotateX(theta) { var cosTheta = Math.cos(theta); var sinTheta = Math.sin(theta); return [1, 0, 0, 0, 0, cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1]; }; /** * Return a Transform which represents a clockwise * rotation around the y axis. * * @method rotateY * @static * @param {Number} theta radians * @return {Transform} */ Transform.rotateY = function rotateY(theta) { var cosTheta = Math.cos(theta); var sinTheta = Math.sin(theta); return [cosTheta, 0, -sinTheta, 0, 0, 1, 0, 0, sinTheta, 0, cosTheta, 0, 0, 0, 0, 1]; }; /** * Return a Transform which represents a clockwise * rotation around the z axis. * * @method rotateZ * @static * @param {Number} theta radians * @return {Transform} */ Transform.rotateZ = function rotateZ(theta) { var cosTheta = Math.cos(theta); var sinTheta = Math.sin(theta); return [cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; }; /** * Return a Transform which represents composed clockwise * rotations along each of the axes. Equivalent to the result of * Matrix.multiply(rotateX(phi), rotateY(theta), rotateZ(psi)). * * @method rotate * @static * @param {Number} phi radians to rotate about the positive x axis * @param {Number} theta radians to rotate about the positive y axis * @param {Number} psi radians to rotate about the positive z axis * @return {Transform} */ Transform.rotate = function rotate(phi, theta, psi) { var cosPhi = Math.cos(phi); var sinPhi = Math.sin(phi); var cosTheta = Math.cos(theta); var sinTheta = Math.sin(theta); var cosPsi = Math.cos(psi); var sinPsi = Math.sin(psi); var result = [ cosTheta * cosPsi, cosPhi * sinPsi + sinPhi * sinTheta * cosPsi, sinPhi * sinPsi - cosPhi * sinTheta * cosPsi, 0, -cosTheta * sinPsi, cosPhi * cosPsi - sinPhi * sinTheta * sinPsi, sinPhi * cosPsi + cosPhi * sinTheta * sinPsi, 0, sinTheta, -sinPhi * cosTheta, cosPhi * cosTheta, 0, 0, 0, 0, 1 ]; return result; }; /** * Return a Transform which represents an axis-angle rotation * * @method rotateAxis * @static * @param {Array.Number} v unit vector representing the axis to rotate about * @param {Number} theta radians to rotate clockwise about the axis * @return {Transform} */ Transform.rotateAxis = function rotateAxis(v, theta) { var sinTheta = Math.sin(theta); var cosTheta = Math.cos(theta); var verTheta = 1 - cosTheta; // versine of theta var xxV = v[0] * v[0] * verTheta; var xyV = v[0] * v[1] * verTheta; var xzV = v[0] * v[2] * verTheta; var yyV = v[1] * v[1] * verTheta; var yzV = v[1] * v[2] * verTheta; var zzV = v[2] * v[2] * verTheta; var xs = v[0] * sinTheta; var ys = v[1] * sinTheta; var zs = v[2] * sinTheta; var result = [ xxV + cosTheta, xyV + zs, xzV - ys, 0, xyV - zs, yyV + cosTheta, yzV + xs, 0, xzV + ys, yzV - xs, zzV + cosTheta, 0, 0, 0, 0, 1 ]; return result; }; /** * Return a Transform which represents a transform matrix applied about * a separate origin point. * * @method aboutOrigin * @static * @param {Array.Number} v origin point to apply matrix * @param {Transform} m matrix to apply * @return {Transform} */ Transform.aboutOrigin = function aboutOrigin(v, m) { var t0 = v[0] - (v[0] * m[0] + v[1] * m[4] + v[2] * m[8]); var t1 = v[1] - (v[0] * m[1] + v[1] * m[5] + v[2] * m[9]); var t2 = v[2] - (v[0] * m[2] + v[1] * m[6] + v[2] * m[10]); return Transform.thenMove(m, [t0, t1, t2]); }; /** * Return a Transform representation of a skew transformation * * @method skew * @static * @param {Number} phi scale factor skew in the x axis * @param {Number} theta scale factor skew in the y axis * @param {Number} psi scale factor skew in the z axis * @return {Transform} */ Transform.skew = function skew(phi, theta, psi) { return [1, Math.tan(theta), 0, 0, Math.tan(psi), 1, 0, 0, 0, Math.tan(phi), 1, 0, 0, 0, 0, 1]; }; /** * Return a Transform representation of a skew in the x-direction * * @method skewX * @static * @param {Number} angle the angle between the top and left sides * @return {Transform} */ Transform.skewX = function skewX(angle) { return [1, 0, 0, 0, Math.tan(angle), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; }; /** * Return a Transform representation of a skew in the y-direction * * @method skewY * @static * @param {Number} angle the angle between the top and right sides * @return {Transform} */ Transform.skewY = function skewY(angle) { return [1, Math.tan(angle), 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; }; /** * Returns a perspective Transform matrix * * @method perspective * @static * @param {Number} focusZ z position of focal point * @return {Transform} */ Transform.perspective = function perspective(focusZ) { return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1 / focusZ, 0, 0, 0, 1]; }; /** * Return translation vector component of given Transform * * @method getTranslate * @static * @param {Transform} m Transform * @return {Array.Number} the translation vector [t_x, t_y, t_z] */ Transform.getTranslate = function getTranslate(m) { return [m[12], m[13], m[14]]; }; /** * Return inverse affine transform for given Transform. * Note: This assumes m[3] = m[7] = m[11] = 0, and m[15] = 1. * Will provide incorrect results if not invertible or preconditions not met. * * @method inverse * @static * @param {Transform} m Transform * @return {Transform} */ Transform.inverse = function inverse(m) { // only need to consider 3x3 section for affine var c0 = m[5] * m[10] - m[6] * m[9]; var c1 = m[4] * m[10] - m[6] * m[8]; var c2 = m[4] * m[9] - m[5] * m[8]; var c4 = m[1] * m[10] - m[2] * m[9]; var c5 = m[0] * m[10] - m[2] * m[8]; var c6 = m[0] * m[9] - m[1] * m[8]; var c8 = m[1] * m[6] - m[2] * m[5]; var c9 = m[0] * m[6] - m[2] * m[4]; var c10 = m[0] * m[5] - m[1] * m[4]; var detM = m[0] * c0 - m[1] * c1 + m[2] * c2; var invD = 1 / detM; var result = [ invD * c0, -invD * c4, invD * c8, 0, -invD * c1, invD * c5, -invD * c9, 0, invD * c2, -invD * c6, invD * c10, 0, 0, 0, 0, 1 ]; result[12] = -m[12] * result[0] - m[13] * result[4] - m[14] * result[8]; result[13] = -m[12] * result[1] - m[13] * result[5] - m[14] * result[9]; result[14] = -m[12] * result[2] - m[13] * result[6] - m[14] * result[10]; return result; }; /** * Returns the transpose of a 4x4 matrix * * @method transpose * @static * @param {Transform} m matrix * @return {Transform} the resulting transposed matrix */ Transform.transpose = function transpose(m) { return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]]; }; function _normSquared(v) { return (v.length === 2) ? v[0] * v[0] + v[1] * v[1] : v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; } function _norm(v) { return Math.sqrt(_normSquared(v)); } function _sign(n) { return (n < 0) ? -1 : 1; } /** * Decompose Transform into separate .translate, .rotate, .scale, * and .skew components. * * @method interpret * @static * @param {Transform} M transform matrix * @return {Object} matrix spec object with component matrices .translate, * .rotate, .scale, .skew */ Transform.interpret = function interpret(M) { // QR decomposition via Householder reflections //FIRST ITERATION //default Q1 to the identity matrix; var x = [M[0], M[1], M[2]]; // first column vector var sgn = _sign(x[0]); // sign of first component of x (for stability) var xNorm = _norm(x); // norm of first column vector var v = [x[0] + sgn * xNorm, x[1], x[2]]; // v = x + sign(x[0])|x|e1 var mult = 2 / _normSquared(v); // mult = 2/v'v //bail out if our Matrix is singular if (mult >= Infinity) { return {translate: Transform.getTranslate(M), rotate: [0, 0, 0], scale: [0, 0, 0], skew: [0, 0, 0]}; } //evaluate Q1 = I - 2vv'/v'v var Q1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; //diagonals Q1[0] = 1 - mult * v[0] * v[0]; // 0,0 entry Q1[5] = 1 - mult * v[1] * v[1]; // 1,1 entry Q1[10] = 1 - mult * v[2] * v[2]; // 2,2 entry //upper diagonal Q1[1] = -mult * v[0] * v[1]; // 0,1 entry Q1[2] = -mult * v[0] * v[2]; // 0,2 entry Q1[6] = -mult * v[1] * v[2]; // 1,2 entry //lower diagonal Q1[4] = Q1[1]; // 1,0 entry Q1[8] = Q1[2]; // 2,0 entry Q1[9] = Q1[6]; // 2,1 entry //reduce first column of M var MQ1 = Transform.multiply(Q1, M); //SECOND ITERATION on (1,1) minor var x2 = [MQ1[5], MQ1[6]]; var sgn2 = _sign(x2[0]); // sign of first component of x (for stability) var x2Norm = _norm(x2); // norm of first column vector var v2 = [x2[0] + sgn2 * x2Norm, x2[1]]; // v = x + sign(x[0])|x|e1 var mult2 = 2 / _normSquared(v2); // mult = 2/v'v //evaluate Q2 = I - 2vv'/v'v var Q2 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; //diagonal Q2[5] = 1 - mult2 * v2[0] * v2[0]; // 1,1 entry Q2[10] = 1 - mult2 * v2[1] * v2[1]; // 2,2 entry //off diagonals Q2[6] = -mult2 * v2[0] * v2[1]; // 2,1 entry Q2[9] = Q2[6]; // 1,2 entry //calc QR decomposition. Q = Q1*Q2, R = Q'*M var Q = Transform.multiply(Q2, Q1); //note: really Q transpose var R = Transform.multiply(Q, M); //remove negative scaling var remover = Transform.scale(R[0] < 0 ? -1 : 1, R[5] < 0 ? -1 : 1, R[10] < 0 ? -1 : 1); R = Transform.multiply(R, remover); Q = Transform.multiply(remover, Q); //decompose into rotate/scale/skew matrices var result = {}; result.translate = Transform.getTranslate(M); result.rotate = [Math.atan2(-Q[6], Q[10]), Math.asin(Q[2]), Math.atan2(-Q[1], Q[0])]; if (!result.rotate[0]) { result.rotate[0] = 0; result.rotate[2] = Math.atan2(Q[4], Q[5]); } result.scale = [R[0], R[5], R[10]]; result.skew = [Math.atan2(R[9], result.scale[2]), Math.atan2(R[8], result.scale[2]), Math.atan2(R[4], result.scale[0])]; //double rotation workaround if (Math.abs(result.rotate[0]) + Math.abs(result.rotate[2]) > 1.5 * Math.PI) { result.rotate[1] = Math.PI - result.rotate[1]; if (result.rotate[1] > Math.PI) { result.rotate[1] -= 2 * Math.PI; } if (result.rotate[1] < -Math.PI) { result.rotate[1] += 2 * Math.PI; } if (result.rotate[0] < 0) { result.rotate[0] += Math.PI; } else { result.rotate[0] -= Math.PI; } if (result.rotate[2] < 0) { result.rotate[2] += Math.PI; } else { result.rotate[2] -= Math.PI; } } return result; }; /** * Weighted average between two matrices by averaging their * translation, rotation, scale, skew components. * f(M1,M2,t) = (1 - t) * M1 + t * M2 * * @method average * @static * @param {Transform} M1 f(M1,M2,0) = M1 * @param {Transform} M2 f(M1,M2,1) = M2 * @param {Number} t * @return {Transform} */ Transform.average = function average(M1, M2, t) { t = (t === undefined) ? 0.5 : t; var specM1 = Transform.interpret(M1); var specM2 = Transform.interpret(M2); var specAvg = { translate: [0, 0, 0], rotate: [0, 0, 0], scale: [0, 0, 0], skew: [0, 0, 0] }; for (var i = 0; i < 3; i++) { specAvg.translate[i] = (1 - t) * specM1.translate[i] + t * specM2.translate[i]; specAvg.rotate[i] = (1 - t) * specM1.rotate[i] + t * specM2.rotate[i]; specAvg.scale[i] = (1 - t) * specM1.scale[i] + t * specM2.scale[i]; specAvg.skew[i] = (1 - t) * specM1.skew[i] + t * specM2.skew[i]; } return Transform.build(specAvg); }; /** * Compose .translate, .rotate, .scale, .skew components into * Transform matrix * * @method build * @static * @param {matrixSpec} spec object with component matrices .translate, * .rotate, .scale, .skew * @return {Transform} composed transform */ Transform.build = function build(spec) { var scaleMatrix = Transform.scale(spec.scale[0], spec.scale[1], spec.scale[2]); var skewMatrix = Transform.skew(spec.skew[0], spec.skew[1], spec.skew[2]); var rotateMatrix = Transform.rotate(spec.rotate[0], spec.rotate[1], spec.rotate[2]); return Transform.thenMove(Transform.multiply(Transform.multiply(rotateMatrix, skewMatrix), scaleMatrix), spec.translate); }; /** * Determine if two Transforms are component-wise equal * Warning: breaks on perspective Transforms * * @method equals * @static * @param {Transform} a matrix * @param {Transform} b matrix * @return {boolean} */ Transform.equals = function equals(a, b) { return !Transform.notEquals(a, b); }; /** * Determine if two Transforms are component-wise unequal * Warning: breaks on perspective Transforms * * @method notEquals * @static * @param {Transform} a matrix * @param {Transform} b matrix * @return {boolean} */ Transform.notEquals = function notEquals(a, b) { if (a === b) { return false; } // shortci return !(a && b) || a[12] !== b[12] || a[13] !== b[13] || a[14] !== b[14] || a[0] !== b[0] || a[1] !== b[1] || a[2] !== b[2] || a[4] !== b[4] || a[5] !== b[5] || a[6] !== b[6] || a[8] !== b[8] || a[9] !== b[9] || a[10] !== b[10]; }; /** * Constrain angle-trio components to range of [-pi, pi). * * @method normalizeRotation * @static * @param {Array.Number} rotation phi, theta, psi (array of floats * && array.length == 3) * @return {Array.Number} new phi, theta, psi triplet * (array of floats && array.length == 3) */ Transform.normalizeRotation = function normalizeRotation(rotation) { var result = rotation.slice(0); if (result[0] === Math.PI * 0.5 || result[0] === -Math.PI * 0.5) { result[0] = -result[0]; result[1] = Math.PI - result[1]; result[2] -= Math.PI; } if (result[0] > Math.PI * 0.5) { result[0] = result[0] - Math.PI; result[1] = Math.PI - result[1]; result[2] -= Math.PI; } if (result[0] < -Math.PI * 0.5) { result[0] = result[0] + Math.PI; result[1] = -Math.PI - result[1]; result[2] -= Math.PI; } while (result[1] < -Math.PI) { result[1] += 2 * Math.PI; } while (result[1] >= Math.PI) { result[1] -= 2 * Math.PI; } while (result[2] < -Math.PI) { result[2] += 2 * Math.PI; } while (result[2] >= Math.PI) { result[2] -= 2 * Math.PI; } return result; }; /** * (Property) Array defining a translation forward in z by 1 * * @property {array} inFront * @static * @final */ Transform.inFront = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1e-3, 1]; /** * (Property) Array defining a translation backwards in z by 1 * * @property {array} behind * @static * @final */ Transform.behind = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1e-3, 1]; var Transform_1 = Transform; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: mark@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /** * This namespace holds standalone functionality. * Currently includes name mapping for transition curves, * name mapping for origin pairs, and the after() function. * * @class Utility * @static */ var Utility = {}; /** * Table of direction array positions * * @property {object} Direction * @final */ Utility.Direction = { X: 0, Y: 1, Z: 2 }; /** * Return wrapper around callback function. Once the wrapper is called N * times, invoke the callback function. Arguments and scope preserved. * * @method after * * @param {number} count number of calls before callback function invoked * @param {Function} callback wrapped callback function * * @return {function} wrapped callback with coundown feature */ Utility.after = function after(count, callback) { var counter = count; return function() { counter--; if (counter === 0) { callback.apply(this, arguments); } }; }; /** * Load a URL and return its contents in a callback * * @method loadURL * * @param {string} url URL of object * @param {function} callback callback to dispatch with content */ Utility.loadURL = function loadURL(url, callback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function onreadystatechange() { if (this.readyState === 4) { if (callback) { callback(this.responseText); } } }; xhr.open('GET', url); xhr.send(); }; /** * Create a document fragment from a string of HTML * * @method createDocumentFragmentFromHTML * * @param {string} html HTML to convert to DocumentFragment * * @return {DocumentFragment} DocumentFragment representing input HTML */ Utility.createDocumentFragmentFromHTML = function createDocumentFragmentFromHTML(html) { var element = document.createElement('div'); element.innerHTML = html; var result = document.createDocumentFragment(); while (element.hasChildNodes()) { result.appendChild(element.firstChild); } return result; }; /* * Deep clone an object. * @param b {Object} Object to clone * @return a {Object} Cloned object. */ Utility.clone = function clone(b) { var a; if (typeof b === 'object') { a = (b instanceof Array) ? [] : {}; for (var key in b) { if (typeof b[key] === 'object' && b[key] !== null) { if (b[key] instanceof Array) { a[key] = new Array(b[key].length); for (var i = 0; i < b[key].length; i++) { a[key][i] = Utility.clone(b[key][i]); } } else { a[key] = Utility.clone(b[key]); } } else { a[key] = b[key]; } } } else { a = b; } return a; }; var Utility_1 = Utility; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: david@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /*eslint-disable new-cap */ /** * Transition meta-method to support transitioning multiple * values with scalar-only methods. * * * @class MultipleTransition * @constructor * * @param {Object} method Transionable class to multiplex */ function MultipleTransition(method) { this.method = method; this._instances = []; this.state = []; } MultipleTransition.SUPPORTS_MULTIPLE = true; /** * Get the state of each transition. * * @method get * * @return state {Number|Array} state array */ MultipleTransition.prototype.get = function get() { var this\$1 = this; for (var i = 0; i < this._instances.length; i++) { this\$1.state[i] = this\$1._instances[i].get(); } return this.state; }; /** * Set the end states with a shared transition, with optional callback. * * @method set * * @param {Number|Array} endState Final State. Use a multi-element argument for multiple transitions. * @param {Object} transition Transition definition, shared among all instances * @param {Function} callback called when all endStates have been reached. */ MultipleTransition.prototype.set = function set(endState, transition, callback) { var this\$1 = this; var _allCallback = Utility_1.after(endState.length, callback); for (var i = 0; i < endState.length; i++) { if (!this\$1._instances[i]) { this\$1._instances[i] = new (this\$1.method)(); } this\$1._instances[i].set(endState[i], transition, _allCallback); } }; /** * Reset all transitions to start state. * * @method reset * * @param {Number|Array} startState Start state */ MultipleTransition.prototype.reset = function reset(startState) { var this\$1 = this; for (var i = 0; i < startState.length; i++) { if (!this\$1._instances[i]) { this\$1._instances[i] = new (this\$1.method)(); } this\$1._instances[i].reset(startState[i]); } }; var MultipleTransition_1 = MultipleTransition; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: david@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /** * * A state maintainer for a smooth transition between * numerically-specified states. Example numeric states include floats or * Transfornm objects. * * An initial state is set with the constructor or set(startValue). A * corresponding end state and transition are set with set(endValue, * transition). Subsequent calls to set(endValue, transition) begin at * the last state. Calls to get(timestamp) provide the _interpolated state * along the way. * * Note that there is no event loop here - calls to get() are the only way * to find out state projected to the current (or provided) time and are * the only way to trigger callbacks. Usually this kind of object would * be part of the render() path of a visible component. * * @class TweenTransition * @constructor * * @param {Object} options TODO * beginning state */ function TweenTransition(options) { this.options = Object.create(TweenTransition.DEFAULT_OPTIONS); if (options) { this.setOptions(options); } this._startTime = 0; this._startValue = 0; this._updateTime = 0; this._endValue = 0; this._curve = undefined; this._duration = 0; this._active = false; this._callback = undefined; this.state = 0; this.velocity = undefined; } /** * Transition curves mapping independent variable t from domain [0,1] to a * range within [0,1]. Includes functions 'linear', 'easeIn', 'easeOut', * 'easeInOut', 'easeOutBounce', 'spring'. * * @property {object} Curve * @final */ TweenTransition.Curves = { linear: function(t) { return t; }, easeIn: function(t) { return t*t; }, easeOut: function(t) { return t*(2-t); }, easeInOut: function(t) { if (t <= 0.5) { return 2*t*t; } else { return -2*t*t + 4*t - 1; } }, easeOutBounce: function(t) { return t*(3 - 2*t); }, spring: function(t) { return (1 - t) * Math.sin(6 * Math.PI * t) + t; } }; TweenTransition.SUPPORTS_MULTIPLE = true; TweenTransition.DEFAULT_OPTIONS = { curve: TweenTransition.Curves.linear, duration: 500, speed: 0 /* considered only if positive */ }; var registeredCurves = {}; /** * Add "unit" curve to internal dictionary of registered curves. * * @method registerCurve * * @static * * @param {string} curveName dictionary key * @param {unitCurve} curve function of one numeric variable mapping [0,1] * to range inside [0,1] * @return {boolean} false if key is taken, else true */ TweenTransition.registerCurve = function registerCurve(curveName, curve) { if (!registeredCurves[curveName]) { registeredCurves[curveName] = curve; return true; } else { return false; } }; /** * Remove object with key "curveName" from internal dictionary of registered * curves. * * @method unregisterCurve * * @static * * @param {string} curveName dictionary key * @return {boolean} false if key has no dictionary value */ TweenTransition.unregisterCurve = function unregisterCurve(curveName) { if (registeredCurves[curveName]) { delete registeredCurves[curveName]; return true; } else { return false; } }; /** * Retrieve function with key "curveName" from internal dictionary of * registered curves. Default curves are defined in the * TweenTransition.Curves array, where the values represent * unitCurve functions. * * @method getCurve * * @static * * @param {string} curveName dictionary key * @return {unitCurve} curve function of one numeric variable mapping [0,1] * to range inside [0,1] */ TweenTransition.getCurve = function getCurve(curveName) { var curve = registeredCurves[curveName]; if (curve !== undefined) { return curve; } else { throw new Error('curve not registered'); } }; /** * Retrieve all available curves. * * @method getCurves * * @static * * @return {object} curve functions of one numeric variable mapping [0,1] * to range inside [0,1] */ TweenTransition.getCurves = function getCurves() { return registeredCurves; }; // Interpolate: If a linear function f(0) = a, f(1) = b, then return f(t) function _interpolate(a, b, t) { return ((1 - t) * a) + (t * b); } function _clone(obj) { if (obj instanceof Object) { if (obj instanceof Array) { return obj.slice(0); } else { return Object.create(obj); } } else { return obj; } } // Fill in missing properties in "transition" with those in defaultTransition, and // convert internal named curve to function object, returning as new // object. function _normalize(transition, defaultTransition) { var result = {curve: defaultTransition.curve}; if (defaultTransition.duration) { result.duration = defaultTransition.duration; } if (defaultTransition.speed) { result.speed = defaultTransition.speed; } if (transition instanceof Object) { if (transition.duration !== undefined) { result.duration = transition.duration; } if (transition.curve) { result.curve = transition.curve; } if (transition.speed) { result.speed = transition.speed; } } if (typeof result.curve === 'string') { result.curve = TweenTransition.getCurve(result.curve); } return result; } /** * Set internal options, overriding any default options. * * @method setOptions * * * @param {Object} options options object * @param {Object} [options.curve] function mapping [0,1] to [0,1] or identifier * @param {Number} [options.duration] duration in ms * @param {Number} [options.speed] speed in pixels per ms */ TweenTransition.prototype.setOptions = function setOptions(options) { if (options.curve !== undefined) { this.options.curve = options.curve; } if (options.duration !== undefined) { this.options.duration = options.duration; } if (options.speed !== undefined) { this.options.speed = options.speed; } }; /** * Add transition to end state to the queue of pending transitions. Special * Use: calling without a transition resets the object to that state with * no pending actions * * @method set * * * @param {number|FamousMatrix|Array.Number|Object.} endValue * end state to which we _interpolate * @param {transition=} transition object of type {duration: number, curve: * f[0,1] -> [0,1] or name}. If transition is omitted, change will be * instantaneous. * @param {function()=} callback Zero-argument function to call on observed * completion (t=1) */ TweenTransition.prototype.set = function set(endValue, transition, callback) { if (!transition) { this.reset(endValue); if (callback) { callback(); } return; } this._startValue = _clone(this.get()); transition = _normalize(transition, this.options); if (transition.speed) { var startValue = this._startValue; if (startValue instanceof Object) { var variance = 0; for (var i in startValue) { variance += (endValue[i] - startValue[i]) * (endValue[i] - startValue[i]); } transition.duration = Math.sqrt(variance) / transition.speed; } else { transition.duration = Math.abs(endValue - startValue) / transition.speed; } } this._startTime = Date.now(); this._endValue = _clone(endValue); this._startVelocity = _clone(transition.velocity); this._duration = transition.duration; this._curve = transition.curve; this._active = true; this._callback = callback; }; /** * Cancel all transitions and reset to a stable state * * @method reset * * @param {number|Array.Number|Object.} startValue * starting state * @param {number} startVelocity * starting velocity */ TweenTransition.prototype.reset = function reset(startValue, startVelocity) { if (this._callback) { var callback = this._callback; this._callback = undefined; callback(); } this.state = _clone(startValue); this.velocity = _clone(startVelocity); this._startTime = 0; this._duration = 0; this._updateTime = 0; this._startValue = this.state; this._startVelocity = this.velocity; this._endValue = this.state; this._active = false; }; /** * Get current velocity * * @method getVelocity * * @returns {Number} velocity */ TweenTransition.prototype.getVelocity = function getVelocity() { return this.velocity; }; /** * Get interpolated state of current action at provided time. If the last * action has completed, invoke its callback. * * @method get * * * @param {number=} timestamp Evaluate the curve at a normalized version of this * time. If omitted, use current time. (Unix epoch time) * @return {number|Object.} beginning state * _interpolated to this point in time. */ TweenTransition.prototype.get = function get(timestamp) { this.update(timestamp); return this.state; }; function _calculateVelocity(current, start, curve, duration, t) { var velocity; var eps = 1e-7; var speed = (curve(t) - curve(t - eps)) / eps; if (current instanceof Array) { velocity = []; for (var i = 0; i < current.length; i++){ if (typeof current[i] === 'number') { velocity[i] = speed * (current[i] - start[i]) / duration; } else { velocity[i] = 0; } } } else { velocity = speed * (current - start) / duration; } return velocity; } function _calculateState(start, end, t) { var state; if (start instanceof Array) { state = []; for (var i = 0; i < start.length; i++) { if (typeof start[i] === 'number') { state[i] = _interpolate(start[i], end[i], t); } else { state[i] = start[i]; } } } else { state = _interpolate(start, end, t); } return state; } /** * Update internal state to the provided timestamp. This may invoke the last * callback and begin a new action. * * @method update * * * @param {number=} timestamp Evaluate the curve at a normalized version of this * time. If omitted, use current time. (Unix epoch time) */ TweenTransition.prototype.update = function update(timestamp) { if (!this._active) { if (this._callback) { var callback = this._callback; this._callback = undefined; callback(); } return; } if (!timestamp) { timestamp = Date.now(); } if (this._updateTime >= timestamp) { return; } this._updateTime = timestamp; var timeSinceStart = timestamp - this._startTime; if (timeSinceStart >= this._duration) { this.state = this._endValue; this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, 1); this._active = false; } else if (timeSinceStart < 0) { this.state = this._startValue; this.velocity = this._startVelocity; } else { var t = timeSinceStart / this._duration; this.state = _calculateState(this._startValue, this._endValue, this._curve(t)); this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, t); } }; /** * Is there at least one action pending completion? * * @method isActive * * * @return {boolean} */ TweenTransition.prototype.isActive = function isActive() { return this._active; }; /** * Halt transition at current state and erase all pending actions. * * @method halt * */ TweenTransition.prototype.halt = function halt() { this.reset(this.get()); }; // Register all the default curves TweenTransition.registerCurve('linear', TweenTransition.Curves.linear); TweenTransition.registerCurve('easeIn', TweenTransition.Curves.easeIn); TweenTransition.registerCurve('easeOut', TweenTransition.Curves.easeOut); TweenTransition.registerCurve('easeInOut', TweenTransition.Curves.easeInOut); TweenTransition.registerCurve('easeOutBounce', TweenTransition.Curves.easeOutBounce); TweenTransition.registerCurve('spring', TweenTransition.Curves.spring); TweenTransition.customCurve = function customCurve(v1, v2) { v1 = v1 || 0; v2 = v2 || 0; return function(t) { return v1*t + (-2*v1 - v2 + 3)*t*t + (v1 + v2 - 2)*t*t*t; }; }; var TweenTransition_1 = TweenTransition; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: david@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /*eslint-disable new-cap */ /** * A state maintainer for a smooth transition between * numerically-specified states. Example numeric states include floats or * Transform objects. * * An initial state is set with the constructor or set(startState). A * corresponding end state and transition are set with set(endState, * transition). Subsequent calls to set(endState, transition) begin at * the last state. Calls to get(timestamp) provide the interpolated state * along the way. * * Note that there is no event loop here - calls to get() are the only way * to find state projected to the current (or provided) time and are * the only way to trigger callbacks. Usually this kind of object would * be part of the render() path of a visible component. * * @class Transitionable * @constructor * @param {number|Array.Number|Object.} start * beginning state */ function Transitionable(start) { this.currentAction = null; this.actionQueue = []; this.callbackQueue = []; this.state = 0; this.velocity = undefined; this._callback = undefined; this._engineInstance = null; this._currentMethod = null; this.set(start); } var transitionMethods = {}; Transitionable.register = function register(methods) { var success = true; for (var method in methods) { if (!Transitionable.registerMethod(method, methods[method])) { success = false; } } return success; }; Transitionable.registerMethod = function registerMethod(name, engineClass) { if (!(name in transitionMethods)) { transitionMethods[name] = engineClass; return true; } else { return false; } }; Transitionable.unregisterMethod = function unregisterMethod(name) { if (name in transitionMethods) { delete transitionMethods[name]; return true; } else { return false; } }; function _loadNext() { if (this._callback) { var callback = this._callback; this._callback = undefined; callback(); } if (this.actionQueue.length <= 0) { this.set(this.get()); // no update required return; } this.currentAction = this.actionQueue.shift(); this._callback = this.callbackQueue.shift(); var method = null; var endValue = this.currentAction[0]; var transition = this.currentAction[1]; if (transition instanceof Object && transition.method) { method = transition.method; if (typeof method === 'string') { method = transitionMethods[method]; } } else { method = TweenTransition_1; } if (this._currentMethod !== method) { if (!(endValue instanceof Object) || method.SUPPORTS_MULTIPLE === true || endValue.length <= method.SUPPORTS_MULTIPLE) { this._engineInstance = new method(); } else { this._engineInstance = new MultipleTransition_1(method); } this._currentMethod = method; } this._engineInstance.reset(this.state, this.velocity); if (this.velocity !== undefined) { transition.velocity = this.velocity; } this._engineInstance.set(endValue, transition, _loadNext.bind(this)); } /** * Add transition to end state to the queue of pending transitions. Special * Use: calling without a transition resets the object to that state with * no pending actions * * @method set * * @param {number|FamousMatrix|Array.Number|Object.} endState * end state to which we interpolate * @param {transition=} transition object of type {duration: number, curve: * f[0,1] -> [0,1] or name}. If transition is omitted, change will be * instantaneous. * @param {function()=} callback Zero-argument function to call on observed * completion (t=1) */ Transitionable.prototype.set = function set(endState, transition, callback) { if (!transition) { this.reset(endState); if (callback) { callback(); } return this; } var action = [endState, transition]; this.actionQueue.push(action); this.callbackQueue.push(callback); if (!this.currentAction) { _loadNext.call(this); } return this; }; /** * Cancel all transitions and reset to a stable state * * @method reset * * @param {number|Array.Number|Object.} startState * stable state to set to */ Transitionable.prototype.reset = function reset(startState, startVelocity) { this._currentMethod = null; this._engineInstance = null; this._callback = undefined; this.state = startState; this.velocity = startVelocity; this.currentAction = null; this.actionQueue = []; this.callbackQueue = []; }; /** * Add delay action to the pending action queue queue. * * @method delay * * @param {number} duration delay time (ms) * @param {function} callback Zero-argument function to call on observed * completion (t=1) */ Transitionable.prototype.delay = function delay(duration, callback) { var endValue; if (this.actionQueue.length) { endValue = this.actionQueue[this.actionQueue.length - 1][0]; } else if (this.currentAction) { endValue = this.currentAction[0]; } else { endValue = this.get(); } return this.set(endValue, { duration: duration, curve: function() { return 0; }}, callback ); }; /** * Get interpolated state of current action at provided time. If the last * action has completed, invoke its callback. * * @method get * * @param {number=} timestamp Evaluate the curve at a normalized version of this * time. If omitted, use current time. (Unix epoch time) * @return {number|Object.} beginning state * interpolated to this point in time. */ Transitionable.prototype.get = function get(timestamp) { if (this._engineInstance) { if (this._engineInstance.getVelocity) { this.velocity = this._engineInstance.getVelocity(); } this.state = this._engineInstance.get(timestamp); } return this.state; }; /** * Is there at least one action pending completion? * * @method isActive * * @return {boolean} */ Transitionable.prototype.isActive = function isActive() { return !!this.currentAction; }; /** * Halt transition at current state and erase all pending actions. * * @method halt */ Transitionable.prototype.halt = function halt() { return this.set(this.get()); }; var Transitionable_1 = Transitionable; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: david@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /** * A library of curves which map an animation explicitly as a function of time. * * @class Easing */ var Easing = { /** * @property inQuad * @static */ inQuad: function(t) { return t*t; }, /** * @property outQuad * @static */ outQuad: function(t) { return -(t-=1)*t+1; }, /** * @property inOutQuad * @static */ inOutQuad: function(t) { if ((t/=.5) < 1) { return .5*t*t; } return -.5*((--t)*(t-2) - 1); }, /** * @property inCubic * @static */ inCubic: function(t) { return t*t*t; }, /** * @property outCubic * @static */ outCubic: function(t) { return ((--t)*t*t + 1); }, /** * @property inOutCubic * @static */ inOutCubic: function(t) { if ((t/=.5) < 1) { return .5*t*t*t; } return .5*((t-=2)*t*t + 2); }, /** * @property inQuart * @static */ inQuart: function(t) { return t*t*t*t; }, /** * @property outQuart * @static */ outQuart: function(t) { return -((--t)*t*t*t - 1); }, /** * @property inOutQuart * @static */ inOutQuart: function(t) { if ((t/=.5) < 1) { return .5*t*t*t*t; } return -.5 * ((t-=2)*t*t*t - 2); }, /** * @property inQuint * @static */ inQuint: function(t) { return t*t*t*t*t; }, /** * @property outQuint * @static */ outQuint: function(t) { return ((--t)*t*t*t*t + 1); }, /** * @property inOutQuint * @static */ inOutQuint: function(t) { if ((t/=.5) < 1) { return .5*t*t*t*t*t; } return .5*((t-=2)*t*t*t*t + 2); }, /** * @property inSine * @static */ inSine: function(t) { return -1.0*Math.cos(t * (Math.PI/2)) + 1.0; }, /** * @property outSine * @static */ outSine: function(t) { return Math.sin(t * (Math.PI/2)); }, /** * @property inOutSine * @static */ inOutSine: function(t) { return -.5*(Math.cos(Math.PI*t) - 1); }, /** * @property inExpo * @static */ inExpo: function(t) { return (t===0) ? 0.0 : Math.pow(2, 10 * (t - 1)); }, /** * @property outExpo * @static */ outExpo: function(t) { return (t===1.0) ? 1.0 : (-Math.pow(2, -10 * t) + 1); }, /** * @property inOutExpo * @static */ inOutExpo: function(t) { if (t===0) { return 0.0; } if (t===1.0) { return 1.0; } if ((t/=.5) < 1) { return .5 * Math.pow(2, 10 * (t - 1)); } return .5 * (-Math.pow(2, -10 * --t) + 2); }, /** * @property inCirc * @static */ inCirc: function(t) { return -(Math.sqrt(1 - t*t) - 1); }, /** * @property outCirc * @static */ outCirc: function(t) { return Math.sqrt(1 - (--t)*t); }, /** * @property inOutCirc * @static */ inOutCirc: function(t) { if ((t/=.5) < 1) { return -.5 * (Math.sqrt(1 - t*t) - 1); } return .5 * (Math.sqrt(1 - (t-=2)*t) + 1); }, /** * @property inElastic * @static */ inElastic: function(t) { var s=1.70158;var p=0;var a=1.0; if (t===0) { return 0.0; } if (t===1) { return 1.0; } if (!p) { p=.3; } s = p/(2*Math.PI) * Math.asin(1.0/a); return -(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/ p)); }, /** * @property outElastic * @static */ outElastic: function(t) { var s=1.70158;var p=0;var a=1.0; if (t===0) { return 0.0; } if (t===1) { return 1.0; } if (!p) { p=.3; } s = p/(2*Math.PI) * Math.asin(1.0/a); return a*Math.pow(2,-10*t) * Math.sin((t-s)*(2*Math.PI)/p) + 1.0; }, /** * @property inOutElastic * @static */ inOutElastic: function(t) { var s=1.70158;var p=0;var a=1.0; if (t===0) { return 0.0; } if ((t/=.5)===2) { return 1.0; } if (!p) { p=(.3*1.5); } s = p/(2*Math.PI) * Math.asin(1.0/a); if (t < 1) { return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p)); } return a*Math.pow(2,-10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p)*.5 + 1.0; }, /** * @property inBack * @static */ inBack: function(t, s) { if (s === undefined) { s = 1.70158; } return t*t*((s+1)*t - s); }, /** * @property outBack * @static */ outBack: function(t, s) { if (s === undefined) { s = 1.70158; } return ((--t)*t*((s+1)*t + s) + 1); }, /** * @property inOutBack * @static */ inOutBack: function(t, s) { if (s === undefined) { s = 1.70158; } if ((t/=.5) < 1) { return .5*(t*t*(((s*=(1.525))+1)*t - s)); } return .5*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2); }, /** * @property inBounce * @static */ inBounce: function(t) { return 1.0 - Easing.outBounce(1.0-t); }, /** * @property outBounce * @static */ outBounce: function(t) { if (t < (1/2.75)) { return (7.5625*t*t); } else if (t < (2/2.75)) { return (7.5625*(t-=(1.5/2.75))*t + .75); } else if (t < (2.5/2.75)) { return (7.5625*(t-=(2.25/2.75))*t + .9375); } else { return (7.5625*(t-=(2.625/2.75))*t + .984375); } }, /** * @property inOutBounce * @static */ inOutBounce: function(t) { if (t < .5) { return Easing.inBounce(t*2) * .5; } return Easing.outBounce(t*2-1.0) * .5 + .5; } }; var Easing_1 = Easing; /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Owner: david@famo.us * @license MPL 2.0 * @copyright Famous Industries, Inc. 2015 */ /** * A class for transitioning the state of a Transform by transitioning the * X, Y, and Z axes of it's translate, scale, skew and rotate components * independently. * * @class TransitionableTransform * @constructor * * @param [transform=Transform.identity] {Transform} The initial transform state */ function TransitionableTransform(transform) { var this\$1 = this; this._final = Transform_1.identity.slice(); this._finalTranslate = [0, 0, 0]; this._finalRotate = [0, 0, 0]; this._finalSkew = [0, 0, 0]; this._finalScale = [1, 1, 1]; this.translate = []; this.rotate = []; this.skew = []; this.scale = []; for (var i=0; i<3; i+=1) { this\$1.translate[i] = new Transitionable_1(this\$1._finalTranslate[i]); this\$1.rotate[i] = new Transitionable_1(this\$1._finalRotate[i]); this\$1.skew[i] = new Transitionable_1(this\$1._finalSkew[i]); this\$1.scale[i] = new Transitionable_1(this\$1._finalScale[i]); } if (transform) { this.set(transform); } } function _build() { return Transform_1.build({ translate: [this.translate[0].get(), this.translate[1].get(), this.translate[2].get()], rotate: [this.rotate[0].get(), this.rotate[1].get(), this.rotate[2].get()], skew: [this.skew[0].get(), this.skew[1].get(), this.skew[2].get()], scale: [this.scale[0].get(), this.scale[1].get(), this.scale[2].get()] }); } function _buildFinal() { return Transform_1.build({ translate: this._finalTranslate, rotate: this._finalRotate, skew: this._finalSkew, scale: this._finalScale }); } function _countOfType(array, type) { var count = 0; for (var i=0; i