1/** 2 * https://animejs.com 3 * JavaScript animation engine 4 * @version v2.2.0 5 * @author Julian Garnier 6 * @copyright ©2017 Julian Garnier 7 * Released under the MIT license 8**/ 9 10(function(root, factory) { 11 if (typeof define === 'function' && define.amd) { 12 // AMD. Register as an anonymous module. 13 define([], factory); 14 } else if (typeof module === 'object' && module.exports) { 15 // Node. Does not work with strict CommonJS, but 16 // only CommonJS-like environments that support module.exports, 17 // like Node. 18 module.exports = factory(); 19 } else { 20 // Browser globals (root is window) 21 root.anime = factory(); 22 } 23}(this, () => { 24 25 // Defaults 26 27 const defaultInstanceSettings = { 28 update: undefined, 29 begin: undefined, 30 run: undefined, 31 complete: undefined, 32 loop: 1, 33 direction: 'normal', 34 autoplay: true, 35 offset: 0 36 } 37 38 const defaultTweenSettings = { 39 duration: 1000, 40 delay: 0, 41 easing: 'easeOutElastic', 42 elasticity: 500, 43 round: 0 44 } 45 46 const validTransforms = ['translateX', 'translateY', 'translateZ', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scaleX', 'scaleY', 'scaleZ', 'skewX', 'skewY', 'perspective']; 47 let transformString; 48 49 // Utils 50 51 function stringContains(str, text) { 52 return str.indexOf(text) > -1; 53 } 54 55 const is = { 56 arr: a => Array.isArray(a), 57 obj: a => stringContains(Object.prototype.toString.call(a), 'Object'), 58 pth: a => is.obj(a) && a.hasOwnProperty('totalLength'), 59 svg: a => a instanceof SVGElement, 60 dom: a => a.nodeType || is.svg(a), 61 str: a => typeof a === 'string', 62 fnc: a => typeof a === 'function', 63 und: a => typeof a === 'undefined', 64 hex: a => /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a), 65 rgb: a => /^rgb/.test(a), 66 hsl: a => /^hsl/.test(a), 67 col: a => (is.hex(a) || is.rgb(a) || is.hsl(a)) 68 } 69 70 // BezierEasing https://github.com/gre/bezier-easing 71 72 const bezier = (() => { 73 74 const kSplineTableSize = 11; 75 const kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); 76 77 function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1 }; 78 function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1 }; 79 function C (aA1) { return 3.0 * aA1 }; 80 81 function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT }; 82 function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1) }; 83 84 function binarySubdivide (aX, aA, aB, mX1, mX2) { 85 let currentX, currentT, i = 0; 86 do { 87 currentT = aA + (aB - aA) / 2.0; 88 currentX = calcBezier(currentT, mX1, mX2) - aX; 89 if (currentX > 0.0) { aB = currentT } else { aA = currentT }; 90 } while (Math.abs(currentX) > 0.0000001 && ++i < 10); 91 return currentT; 92 } 93 94 function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { 95 for (let i = 0; i < 4; ++i) { 96 const currentSlope = getSlope(aGuessT, mX1, mX2); 97 if (currentSlope === 0.0) return aGuessT; 98 const currentX = calcBezier(aGuessT, mX1, mX2) - aX; 99 aGuessT -= currentX / currentSlope; 100 } 101 return aGuessT; 102 } 103 104 function bezier(mX1, mY1, mX2, mY2) { 105 106 if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) return; 107 let sampleValues = new Float32Array(kSplineTableSize); 108 109 if (mX1 !== mY1 || mX2 !== mY2) { 110 for (let i = 0; i < kSplineTableSize; ++i) { 111 sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); 112 } 113 } 114 115 function getTForX(aX) { 116 117 let intervalStart = 0.0; 118 let currentSample = 1; 119 const lastSample = kSplineTableSize - 1; 120 121 for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { 122 intervalStart += kSampleStepSize; 123 } 124 125 --currentSample; 126 127 const dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); 128 const guessForT = intervalStart + dist * kSampleStepSize; 129 const initialSlope = getSlope(guessForT, mX1, mX2); 130 131 if (initialSlope >= 0.001) { 132 return newtonRaphsonIterate(aX, guessForT, mX1, mX2); 133 } else if (initialSlope === 0.0) { 134 return guessForT; 135 } else { 136 return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); 137 } 138 139 } 140 141 return x => { 142 if (mX1 === mY1 && mX2 === mY2) return x; 143 if (x === 0) return 0; 144 if (x === 1) return 1; 145 return calcBezier(getTForX(x), mY1, mY2); 146 } 147 148 } 149 150 return bezier; 151 152 })(); 153 154 const easings = (() => { 155 156 const names = ['Quad', 'Cubic', 'Quart', 'Quint', 'Sine', 'Expo', 'Circ', 'Back', 'Elastic']; 157 158 // Elastic easing adapted from jQueryUI http://api.jqueryui.com/easings/ 159 160 function elastic(t, p) { 161 return t === 0 || t === 1 ? t : 162 -Math.pow(2, 10 * (t - 1)) * Math.sin((((t - 1) - (p / (Math.PI * 2.0) * Math.asin(1))) * (Math.PI * 2)) / p ); 163 } 164 165 // Approximated Penner equations http://matthewlein.com/ceaser/ 166 167 const equations = { 168 In: [ 169 [0.550, 0.085, 0.680, 0.530], /* InQuad */ 170 [0.550, 0.055, 0.675, 0.190], /* InCubic */ 171 [0.895, 0.030, 0.685, 0.220], /* InQuart */ 172 [0.755, 0.050, 0.855, 0.060], /* InQuint */ 173 [0.470, 0.000, 0.745, 0.715], /* InSine */ 174 [0.950, 0.050, 0.795, 0.035], /* InExpo */ 175 [0.600, 0.040, 0.980, 0.335], /* InCirc */ 176 [0.600, -0.280, 0.735, 0.045], /* InBack */ 177 elastic /* InElastic */ 178 ], Out: [ 179 [0.250, 0.460, 0.450, 0.940], /* OutQuad */ 180 [0.215, 0.610, 0.355, 1.000], /* OutCubic */ 181 [0.165, 0.840, 0.440, 1.000], /* OutQuart */ 182 [0.230, 1.000, 0.320, 1.000], /* OutQuint */ 183 [0.390, 0.575, 0.565, 1.000], /* OutSine */ 184 [0.190, 1.000, 0.220, 1.000], /* OutExpo */ 185 [0.075, 0.820, 0.165, 1.000], /* OutCirc */ 186 [0.175, 0.885, 0.320, 1.275], /* OutBack */ 187 (t, f) => 1 - elastic(1 - t, f) /* OutElastic */ 188 ], InOut: [ 189 [0.455, 0.030, 0.515, 0.955], /* InOutQuad */ 190 [0.645, 0.045, 0.355, 1.000], /* InOutCubic */ 191 [0.770, 0.000, 0.175, 1.000], /* InOutQuart */ 192 [0.860, 0.000, 0.070, 1.000], /* InOutQuint */ 193 [0.445, 0.050, 0.550, 0.950], /* InOutSine */ 194 [1.000, 0.000, 0.000, 1.000], /* InOutExpo */ 195 [0.785, 0.135, 0.150, 0.860], /* InOutCirc */ 196 [0.680, -0.550, 0.265, 1.550], /* InOutBack */ 197 (t, f) => t < .5 ? elastic(t * 2, f) / 2 : 1 - elastic(t * -2 + 2, f) / 2 /* InOutElastic */ 198 ] 199 } 200 201 let functions = { 202 linear: bezier(0.250, 0.250, 0.750, 0.750) 203 } 204 205 for (let type in equations) { 206 equations[type].forEach((f, i) => { 207 functions['ease'+type+names[i]] = is.fnc(f) ? f : bezier.apply(this, f); 208 }); 209 } 210 211 return functions; 212 213 })(); 214 215 // Strings 216 217 function stringToHyphens(str) { 218 return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); 219 } 220
221 function selectString(str) { 222 if (is.col(str)) return; 223 try { 224 let nodes = document.querySelectorAll(str); 225 return nodes; 226 } catch(e) { 227 return; 228 } 229 } 230 231 // Arrays 232 233 function filterArray(arr, callback) { 234 const len = arr.length; 235 const thisArg = arguments.length >= 2 ? arguments[1] : void 0; 236 let result = []; 237 for (let i = 0; i < len; i++) { 238 if (i in arr) { 239 const val = arr[i]; 240 if (callback.call(thisArg, val, i, arr)) { 241 result.push(val); 242 } 243 } 244 } 245 return result; 246 } 247 248 function flattenArray(arr) { 249 return arr.reduce((a, b) => a.concat(is.arr(b) ? flattenArray(b) : b), []); 250 } 251 252 function toArray(o) { 253 if (is.arr(o)) return o; 254 if (is.str(o)) o = selectString(o) || o; 255 if (o instanceof NodeList || o instanceof HTMLCollection) return [].slice.call(o); 256 return [o]; 257 } 258 259 function arrayContains(arr, val) { 260 return arr.some(a => a === val); 261 } 262 263 // Objects 264 265 function cloneObject(o) { 266 let clone = {}; 267 for (let p in o) clone[p] = o[p]; 268 return clone; 269 } 270 271 function replaceObjectProps(o1, o2) { 272 let o = cloneObject(o1); 273 for (let p in o1) o[p] = o2.hasOwnProperty(p) ? o2[p] : o1[p]; 274 return o; 275 } 276 277 function mergeObjects(o1, o2) { 278 let o = cloneObject(o1); 279 for (let p in o2) o[p] = is.und(o1[p]) ? o2[p] : o1[p]; 280 return o; 281 } 282 283 // Colors 284 285 function rgbToRgba(rgbValue) { 286 const rgb = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(rgbValue); 287 return rgb ? `rgba(${rgb[1]},1)` : rgbValue; 288 } 289 290 function hexToRgba(hexValue) { 291 const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 292 const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b ); 293 const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 294 const r = parseInt(rgb[1], 16); 295 const g = parseInt(rgb[2], 16); 296 const b = parseInt(rgb[3], 16); 297 return `rgba(${r},${g},${b},1)`; 298 } 299 300 function hslToRgba(hslValue) { 301 const hsl = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(hslValue) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(hslValue); 302 const h = parseInt(hsl[1]) / 360; 303 const s = parseInt(hsl[2]) / 100; 304 const l = parseInt(hsl[3]) / 100; 305 const a = hsl[4] || 1; 306 function hue2rgb(p, q, t) { 307 if (t < 0) t += 1; 308 if (t > 1) t -= 1; 309 if (t < 1/6) return p + (q - p) * 6 * t; 310 if (t < 1/2) return q; 311 if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; 312 return p; 313 } 314 let r, g, b; 315 if (s == 0) { 316 r = g = b = l; 317 } else { 318 const q = l < 0.5 ? l * (1 + s) : l + s - l * s; 319 const p = 2 * l - q; 320 r = hue2rgb(p, q, h + 1/3); 321 g = hue2rgb(p, q, h); 322 b = hue2rgb(p, q, h - 1/3); 323 } 324 return `rgba(${r * 255},${g * 255},${b * 255},${a})`; 325 } 326 327 function colorToRgb(val) { 328 if (is.rgb(val)) return rgbToRgba(val); 329 if (is.hex(val)) return hexToRgba(val); 330 if (is.hsl(val)) return hslToRgba(val); 331 } 332 333 // Units 334 335 function getUnit(val) { 336 const split = /([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(val); 337 if (split) return split[2]; 338 } 339 340 function getTransformUnit(propName) { 341 if (stringContains(propName, 'translate') || propName === 'perspective') return 'px'; 342 if (stringContains(propName, 'rotate') || stringContains(propName, 'skew')) return 'deg'; 343 } 344 345 // Values 346 347 function minMaxValue(val, min, max) { 348 return Math.min(Math.max(val, min), max); 349 } 350 351 function getFunctionValue(val, animatable) { 352 if (!is.fnc(val)) return val; 353 return val(animatable.target, animatable.id, animatable.total); 354 } 355 356 function getCSSValue(el, prop) { 357 if (prop in el.style) { 358 return getComputedStyle(el).getPropertyValue(stringToHyphens(prop)) || '0'; 359 } 360 } 361 362 function getAnimationType(el, prop) { 363 if (is.dom(el) && arrayContains(validTransforms, prop)) return 'transform'; 364 if (is.dom(el) && (el.getAttribute(prop) || (is.svg(el) && el[prop]))) return 'attribute'; 365 if (is.dom(el) && (prop !== 'transform' && getCSSValue(el, prop))) return 'css'; 366 if (el[prop] != null) return 'object'; 367 } 368 369 function getTransformValue(el, propName) { 370 const defaultUnit = getTransformUnit(propName); 371 const defaultVal = stringContains(propName, 'scale') ? 1 : 0 + defaultUnit; 372 const str = el.style.transform; 373 if (!str) return defaultVal; 374 let match = []; 375 let props = []; 376 let values = []; 377 const rgx = /(\w+)\((.+?)\)/g; 378 while (match = rgx.exec(str)) { 379 props.push(match[1]); 380 values.push(match[2]); 381 } 382 const value = filterArray(values, (val, i) => props[i] === propName); 383 return value.length ? value[0] : defaultVal; 384 } 385 386 function getOriginalTargetValue(target, propName) { 387 switch (getAnimationType(target, propName)) { 388 case 'transform': return getTransformValue(target, propName); 389 case 'css': return getCSSValue(target, propName); 390 case 'attribute': return target.getAttribute(propName); 391 } 392 return target[propName] || 0; 393 } 394 395 function getRelativeValue(to, from) { 396 const operator = /^(\*=|\+=|-=)/.exec(to); 397 if (!operator) return to; 398 const u = getUnit(to) || 0; 399 const x = parseFloat(from); 400 const y = parseFloat(to.replace(operator[0], '')); 401 switch (operator[0][0]) { 402 case '+': return x + y + u; 403 case '-': return x - y + u; 404 case '*': return x * y + u; 405 } 406 } 407 408 function validateValue(val, unit) { 409 if (is.col(val)) return colorToRgb(val); 410 const originalUnit = getUnit(val); 411 const unitLess = originalUnit ? val.substr(0, val.length - originalUnit.length) : val; 412 return unit && !/\s/g.test(val) ? unitLess + unit : unitLess; 413 } 414 415 // getTotalLength() equivalent for circle, rect, polyline, polygon and line shapes. 416 // adapted from https://gist.github.com/SebLambla/3e0550c496c236709744 417 418 function getDistance(p1, p2) { 419 return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)); 420 } 421 422 function getCircleLength(el) { 423 return 2 * Math.PI * el.getAttribute('r'); 424 } 425 426 function getRectLength(el) { 427 return (el.getAttribute('width') * 2) + (el.getAttribute('height') * 2); 428 } 429 430 function getLineLength(el) { 431 return getDistance( 432 {x: el.getAttribute('x1'), y: el.getAttribute('y1')}, 433 {x: el.getAttribute('x2'), y: el.getAttribute('y2')} 434 ); 435 } 436 437 function getPolylineLength(el) { 438 const points = el.points; 439 let totalLength = 0; 440 let previousPos; 441 for (let i = 0 ; i < points.numberOfItems; i++) { 442 const currentPos = points.getItem(i); 443 if (i > 0) totalLength += getDistance(previousPos, currentPos); 444 previousPos = currentPos; 445 } 446 return totalLength; 447 } 448 449 function getPolygonLength(el) { 450 const points = el.points; 451 return getPolylineLength(el) + getDistance(points.getItem(points.numberOfItems - 1), points.getItem(0)); 452 } 453 454 // Path animation 455 456 function getTotalLength(el) { 457 if (el.getTotalLength) return el.getTotalLength(); 458 switch(el.tagName.toLowerCase()) { 459 case 'circle': return getCircleLength(el); 460 case 'rect': return getRectLength(el); 461 case 'line': return getLineLength(el); 462 case 'polyline': return getPolylineLength(el); 463 case 'polygon': return getPolygonLength(el); 464 } 465 } 466 467 function setDashoffset(el) { 468 const pathLength = getTotalLength(el); 469 el.setAttribute('stroke-dasharray', pathLength); 470 return pathLength; 471 } 472 473 // Motion path 474 475 function getPath(path, percent) {
476 const el = is.str(path) ? selectString(path)[0] : path; 477 const p = percent || 100; 478 return function(prop) { 479 return { 480 el: el, 481 property: prop, 482 totalLength: getTotalLength(el) * (p / 100) 483 } 484 } 485 } 486 487 function getPathProgress(path, progress) { 488 function point(offset = 0) { 489 const l = progress + offset >= 1 ? progress + offset : 0; 490 return path.el.getPointAtLength(l); 491 } 492 const p = point(); 493 const p0 = point(-1); 494 const p1 = point(+1); 495 switch (path.property) { 496 case 'x': return p.x; 497 case 'y': return p.y; 498 case 'angle': return Math.atan2(p1.y - p0.y, p1.x - p0.x) * 180 / Math.PI; 499 } 500 } 501 502 // Decompose value 503 504 function decomposeValue(val, unit) { 505 const rgx = /-?\d*\.?\d+/g; 506 const value = validateValue((is.pth(val) ? val.totalLength : val), unit) + ''; 507 return { 508 original: value, 509 numbers: value.match(rgx) ? value.match(rgx).map(Number) : [0], 510 strings: (is.str(val) || unit) ? value.split(rgx) : [] 511 } 512 } 513 514 // Animatables 515 516 function parseTargets(targets) { 517 const targetsArray = targets ? (flattenArray(is.arr(targets) ? targets.map(toArray) : toArray(targets))) : []; 518 return filterArray(targetsArray, (item, pos, self) => self.indexOf(item) === pos); 519 } 520 521 function getAnimatables(targets) { 522 const parsed = parseTargets(targets); 523 return parsed.map((t, i) => { 524 return {target: t, id: i, total: parsed.length}; 525 }); 526 } 527 528 // Properties 529 530 function normalizePropertyTweens(prop, tweenSettings) { 531 let settings = cloneObject(tweenSettings); 532 if (is.arr(prop)) { 533 const l = prop.length; 534 const isFromTo = (l === 2 && !is.obj(prop[0])); 535 if (!isFromTo) { 536 // Duration divided by the number of tweens 537 if (!is.fnc(tweenSettings.duration)) settings.duration = tweenSettings.duration / l; 538 } else { 539 // Transform [from, to] values shorthand to a valid tween value 540 prop = {value: prop}; 541 } 542 } 543 return toArray(prop).map((v, i) => { 544 // Default delay value should be applied only on the first tween 545 const delay = !i ? tweenSettings.delay : 0; 546 // Use path object as a tween value 547 let obj = is.obj(v) && !is.pth(v) ? v : {value: v}; 548 // Set default delay value 549 if (is.und(obj.delay)) obj.delay = delay; 550 return obj; 551 }).map(k => mergeObjects(k, settings)); 552 } 553 554 function getProperties(instanceSettings, tweenSettings, params) { 555 let properties = []; 556 const settings = mergeObjects(instanceSettings, tweenSettings); 557 for (let p in params) { 558 if (!settings.hasOwnProperty(p) && p !== 'targets') { 559 properties.push({ 560 name: p, 561 offset: settings['offset'], 562 tweens: normalizePropertyTweens(params[p], tweenSettings) 563 }); 564 } 565 } 566 return properties; 567 } 568 569 // Tweens 570 571 function normalizeTweenValues(tween, animatable) { 572 let t = {}; 573 for (let p in tween) { 574 let value = getFunctionValue(tween[p], animatable); 575 if (is.arr(value)) { 576 value = value.map(v => getFunctionValue(v, animatable)); 577 if (value.length === 1) value = value[0]; 578 } 579 t[p] = value; 580 } 581 t.duration = parseFloat(t.duration); 582 t.delay = parseFloat(t.delay); 583 return t; 584 } 585 586 function normalizeEasing(val) { 587 return is.arr(val) ? bezier.apply(this, val) : easings[val]; 588 } 589 590 function normalizeTweens(prop, animatable) { 591 let previousTween; 592 return prop.tweens.map(t => { 593 let tween = normalizeTweenValues(t, animatable); 594 const tweenValue = tween.value; 595 const originalValue = getOriginalTargetValue(animatable.target, prop.name); 596 const previousValue = previousTween ? previousTween.to.original : originalValue; 597 const from = is.arr(tweenValue) ? tweenValue[0] : previousValue; 598 const to = getRelativeValue(is.arr(tweenValue) ? tweenValue[1] : tweenValue, from); 599 const unit = getUnit(to) || getUnit(from) || getUnit(originalValue); 600 tween.from = decomposeValue(from, unit); 601 tween.to = decomposeValue(to, unit); 602 tween.start = previousTween ? previousTween.end : prop.offset; 603 tween.end = tween.start + tween.delay + tween.duration; 604 tween.easing = normalizeEasing(tween.easing); 605 tween.elasticity = (1000 - minMaxValue(tween.elasticity, 1, 999)) / 1000; 606 tween.isPath = is.pth(tweenValue); 607 tween.isColor = is.col(tween.from.original);
608 if (tween.isColor) tween.round = 1; 609 previousTween = tween; 610 return tween; 611 }); 612 } 613 614 // Tween progress 615 616 const setTweenProgress = { 617 css: (t, p, v) => t.style[p] = v, 618 attribute: (t, p, v) => t.setAttribute(p, v), 619 object: (t, p, v) => t[p] = v, 620 transform: (t, p, v, transforms, id) => { 621 if (!transforms[id]) transforms[id] = []; 622 transforms[id].push(`${p}(${v})`); 623 } 624 } 625 626 // Animations 627 628 function createAnimation(animatable, prop) { 629 const animType = getAnimationType(animatable.target, prop.name); 630 if (animType) { 631 const tweens = normalizeTweens(prop, animatable); 632 return { 633 type: animType, 634 property: prop.name, 635 animatable: animatable, 636 tweens: tweens, 637 duration: tweens[tweens.length - 1].end, 638 delay: tweens[0].delay 639 } 640 } 641 } 642 643 function getAnimations(animatables, properties) { 644 return filterArray(flattenArray(animatables.map(animatable => { 645 return properties.map(prop => { 646 return createAnimation(animatable, prop); 647 }); 648 })), a => !is.und(a)); 649 } 650 651 // Create Instance 652 653 function getInstanceTimings(type, animations, instanceSettings, tweenSettings) { 654 const isDelay = (type === 'delay'); 655 if (animations.length) { 656 return (isDelay ? Math.min : Math.max).apply(Math, animations.map(anim => anim[type])); 657 } else { 658 return isDelay ? tweenSettings.delay : instanceSettings.offset + tweenSettings.delay + tweenSettings.duration; 659 } 660 } 661 662 function createNewInstance(params) { 663 const instanceSettings = replaceObjectProps(defaultInstanceSettings, params); 664 const tweenSettings = replaceObjectProps(defaultTweenSettings, params); 665 const animatables = getAnimatables(params.targets); 666 const properties = getProperties(instanceSettings, tweenSettings, params); 667 const animations = getAnimations(animatables, properties); 668 return mergeObjects(instanceSettings, { 669 children: [], 670 animatables: animatables, 671 animations: animations, 672 duration: getInstanceTimings('duration', animations, instanceSettings, tweenSettings), 673 delay: getInstanceTimings('delay', animations, instanceSettings, tweenSettings) 674 }); 675 } 676 677 // Core 678 679 let activeInstances = []; 680 let raf = 0; 681 682 const engine = (() => { 683 function play() { raf = requestAnimationFrame(step); }; 684 function step(t) { 685 const activeLength = activeInstances.length; 686 if (activeLength) { 687 let i = 0; 688 while (i < activeLength) { 689 if (activeInstances[i]) activeInstances[i].tick(t); 690 i++; 691 } 692 play(); 693 } else { 694 cancelAnimationFrame(raf); 695 raf = 0; 696 } 697 } 698 return play; 699 })(); 700 701 702 // Public Instance 703 704 function anime(params = {}) { 705 706 let now, startTime, lastTime = 0; 707 708 let resolve = null; 709 710 function makePromise(instance) { 711 const promise = window.Promise && new Promise(_resolve => resolve = _resolve); 712 instance.finished = promise; 713 return promise; 714 } 715 716 let instance = createNewInstance(params); 717 718 let promise = makePromise(instance); 719 720 function toggleInstanceDirection() { 721 instance.reversed = !instance.reversed; 722 } 723 724 function adjustTime(time) { 725 return instance.reversed ? instance.duration - time : time; 726 } 727 728 function syncInstanceChildren(time) { 729 const children = instance.children; 730 const childrenLength = children.length; 731 if (time >= instance.currentTime) { 732 for (let i = 0; i < childrenLength; i++) children[i].seek(time); 733 } else { 734 for (let i = childrenLength; i--;) children[i].seek(time); 735 } 736 } 737 738 function setAnimationsProgress(insTime) { 739 let i = 0; 740 let transforms = {}; 741 const animations = instance.animations; 742 const animationsLength = animations.length; 743 while (i < animationsLength) { 744 const anim = animations[i]; 745 const animatable = anim.animatable; 746 const tweens = anim.tweens; 747 const tweenLength = tweens.length - 1; 748 let tween = tweens[tweenLength]; 749 // Only check for keyframes if there is more than one tween 750 if (tweenLength) tween = filterArray(tweens, t => (insTime < t.end))[0] || tween;
751 const elapsed = minMaxValue(insTime - tween.start - tween.delay, 0, tween.duration) / tween.duration; 752 const eased = isNaN(elapsed) ? 1 : tween.easing(elapsed, tween.elasticity); 753 const strings = tween.to.strings; 754 const round = tween.round; 755 let numbers = []; 756 let progress; 757 const toNumbersLength = tween.to.numbers.length; 758 for (let n = 0; n < toNumbersLength; n++) { 759 let value; 760 const toNumber = tween.to.numbers[n]; 761 const fromNumber = tween.from.numbers[n]; 762 if (!tween.isPath) { 763 value = fromNumber + (eased * (toNumber - fromNumber)); 764 } else { 765 value = getPathProgress(tween.value, eased * toNumber); 766 } 767 if (round) { 768 if (!(tween.isColor && n > 2)) { 769 value = Math.round(value * round) / round; 770 } 771 } 772 numbers.push(value); 773 } 774 // Manual Array.reduce for better performances 775 const stringsLength = strings.length; 776 if (!stringsLength) { 777 progress = numbers[0]; 778 } else { 779 progress = strings[0]; 780 for (let s = 0; s < stringsLength; s++) { 781 const a = strings[s]; 782 const b = strings[s + 1]; 783 const n = numbers[s]; 784 if (!isNaN(n)) { 785 if (!b) { 786 progress += n + ' '; 787 } else { 788 progress += n + b; 789 } 790 } 791 } 792 } 793 setTweenProgress[anim.type](animatable.target, anim.property, progress, transforms, animatable.id); 794 anim.currentValue = progress; 795 i++; 796 } 797 const transformsLength = Object.keys(transforms).length; 798 if (transformsLength) { 799 for (let id = 0; id < transformsLength; id++) { 800 if (!transformString) { 801 const t = 'transform'; 802 transformString = (getCSSValue(document.body, t) ? t : `-webkit-${t}`); 803 } 804 instance.animatables[id].target.style[transformString] = transforms[id].join(' '); 805 } 806 } 807 instance.currentTime = insTime; 808 instance.progress = (insTime / instance.duration) * 100; 809 } 810 811 function setCallback(cb) { 812 if (instance[cb]) instance[cb](instance); 813 } 814 815 function countIteration() { 816 if (instance.remaining && instance.remaining !== true) { 817 instance.remaining--; 818 } 819 } 820 821 function setInstanceProgress(engineTime) { 822 const insDuration = instance.duration; 823 const insOffset = instance.offset; 824 const insStart = insOffset + instance.delay; 825 const insCurrentTime = instance.currentTime; 826 const insReversed = instance.reversed; 827 const insTime = adjustTime(engineTime); 828 if (instance.children.length) syncInstanceChildren(insTime); 829 if (insTime >= insStart || !insDuration) { 830 if (!instance.began) { 831 instance.began = true; 832 setCallback('begin'); 833 } 834 setCallback('run'); 835 } 836 if (insTime > insOffset && insTime < insDuration) { 837 setAnimationsProgress(insTime); 838 } else { 839 if (insTime <= insOffset && insCurrentTime !== 0) { 840 setAnimationsProgress(0); 841 if (insReversed) countIteration(); 842 } 843 if ((insTime >= insDuration && insCurrentTime !== insDuration) || !insDuration) { 844 setAnimationsProgress(insDuration); 845 if (!insReversed) countIteration(); 846 } 847 } 848 setCallback('update'); 849 if (engineTime >= insDuration) { 850 if (instance.remaining) { 851 startTime = now; 852 if (instance.direction === 'alternate') toggleInstanceDirection(); 853 } else { 854 instance.pause(); 855 if (!instance.completed) { 856 instance.completed = true; 857 setCallback('complete'); 858 if ('Promise' in window) { 859 resolve(); 860 promise = makePromise(instance); 861 } 862 } 863 } 864 lastTime = 0; 865 } 866 } 867 868 instance.reset = function() { 869 const direction = instance.direction; 870 const loops = instance.loop; 871 instance.currentTime = 0; 872 instance.progress = 0; 873 instance.paused = true;
874 instance.began = false; 875 instance.completed = false; 876 instance.reversed = direction === 'reverse'; 877 instance.remaining = direction === 'alternate' && loops === 1 ? 2 : loops; 878 setAnimationsProgress(0); 879 for (let i = instance.children.length; i--; ){ 880 instance.children[i].reset(); 881 } 882 } 883 884 instance.tick = function(t) { 885 now = t; 886 if (!startTime) startTime = now; 887 const engineTime = (lastTime + now - startTime) * anime.speed; 888 setInstanceProgress(engineTime); 889 } 890 891 instance.seek = function(time) { 892 setInstanceProgress(adjustTime(time)); 893 } 894 895 instance.pause = function() { 896 const i = activeInstances.indexOf(instance); 897 if (i > -1) activeInstances.splice(i, 1); 898 instance.paused = true; 899 } 900 901 instance.play = function() { 902 if (!instance.paused) return; 903 instance.paused = false; 904 instance.completed = false; 905 startTime = 0; 906 lastTime = adjustTime(instance.currentTime); 907 activeInstances.push(instance); 908 if (!raf) engine(); 909 } 910 911 instance.reverse = function() { 912 toggleInstanceDirection(); 913 startTime = 0; 914 lastTime = adjustTime(instance.currentTime); 915 } 916 917 instance.restart = function() { 918 instance.pause(); 919 instance.reset(); 920 instance.play(); 921 } 922 923 instance.reset(); 924 925 if (instance.autoplay) instance.play(); 926 927 return instance; 928 929 } 930 931 // Remove targets from animation 932 933 function removeTargets(targets) { 934 const targetsArray = parseTargets(targets); 935 for (let i = activeInstances.length; i--;) { 936 const instance = activeInstances[i]; 937 const animations = instance.animations; 938 for (let a = animations.length; a--;) { 939 if (arrayContains(targetsArray, animations[a].animatable.target)) { 940 animations.splice(a, 1); 941 if (!animations.length) instance.pause(); 942 } 943 } 944 } 945 } 946 947 // Timeline 948 949 function timeline(params) { 950 let tl = anime(params); 951 tl.pause(); 952 tl.duration = 0; 953 tl.add = function(instancesParams) { 954 tl.children.forEach(i => { i.began = true; i.completed = true; }); 955 toArray(instancesParams).forEach(instanceParams => { 956 let insParams = mergeObjects(instanceParams, replaceObjectProps(defaultTweenSettings, params || {})); 957 insParams.targets = insParams.targets || params.targets; 958 const tlDuration = tl.duration; 959 const insOffset = insParams.offset; 960 insParams.autoplay = false; 961 insParams.direction = tl.direction; 962 insParams.offset = is.und(insOffset) ? tlDuration : getRelativeValue(insOffset, tlDuration); 963 tl.began = true; 964 tl.completed = true; 965 tl.seek(insParams.offset); 966 const ins = anime(insParams); 967 ins.began = true; 968 ins.completed = true; 969 if (ins.duration > tlDuration) tl.duration = ins.duration; 970 tl.children.push(ins); 971 }); 972 tl.seek(0); 973 tl.reset(); 974 if (tl.autoplay) tl.restart(); 975 return tl; 976 } 977 return tl; 978 } 979 980 anime.version = '2.2.0'; 981 anime.speed = 1; 982 anime.running = activeInstances; 983 anime.remove = removeTargets; 984 anime.getValue = getOriginalTargetValue; 985 anime.path = getPath; 986 anime.setDashoffset = setDashoffset; 987 anime.bezier = bezier; 988 anime.easings = easings; 989 anime.timeline = timeline; 990 anime.random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; 991 992 return anime; 993 994}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.