UNPKG

36.6 kBJavaScriptView Raw
1import { isDefined } from '../util/util';
2/**
3 * @hidden
4 */
5var Animation = (function () {
6 function Animation(plt, ele, opts) {
7 this._dur = null;
8 this._es = null;
9 this._rvEs = null;
10 this.hasChildren = false;
11 this.isPlaying = false;
12 this.hasCompleted = false;
13 this.plt = plt;
14 this.element(ele);
15 this.opts = opts;
16 }
17 Animation.prototype.element = function (ele) {
18 if (ele) {
19 if (typeof ele === 'string') {
20 ele = this.plt.doc().querySelectorAll(ele);
21 for (var i = 0; i < ele.length; i++) {
22 this._addEle(ele[i]);
23 }
24 }
25 else if (ele.length) {
26 for (var i = 0; i < ele.length; i++) {
27 this._addEle(ele[i]);
28 }
29 }
30 else {
31 this._addEle(ele);
32 }
33 }
34 return this;
35 };
36 /**
37 * NO DOM
38 */
39 Animation.prototype._addEle = function (ele) {
40 if (ele.nativeElement) {
41 ele = ele.nativeElement;
42 }
43 if (ele.nodeType === 1) {
44 this._eL = (this._e = this._e || []).push(ele);
45 }
46 };
47 /**
48 * Add a child animation to this animation.
49 */
50 Animation.prototype.add = function (childAnimation) {
51 childAnimation.parent = this;
52 this.hasChildren = true;
53 this._cL = (this._c = this._c || []).push(childAnimation);
54 return this;
55 };
56 /**
57 * Get the duration of this animation. If this animation does
58 * not have a duration, then it'll get the duration from its parent.
59 */
60 Animation.prototype.getDuration = function (opts) {
61 if (opts && isDefined(opts.duration)) {
62 return opts.duration;
63 }
64 else if (this._dur !== null) {
65 return this._dur;
66 }
67 else if (this.parent) {
68 return this.parent.getDuration();
69 }
70 return 0;
71 };
72 /**
73 * Returns if the animation is a root one.
74 */
75 Animation.prototype.isRoot = function () {
76 return !this.parent;
77 };
78 /**
79 * Set the duration for this animation.
80 */
81 Animation.prototype.duration = function (milliseconds) {
82 this._dur = milliseconds;
83 return this;
84 };
85 /**
86 * Get the easing of this animation. If this animation does
87 * not have an easing, then it'll get the easing from its parent.
88 */
89 Animation.prototype.getEasing = function () {
90 if (this._rv && this._rvEs) {
91 return this._rvEs;
92 }
93 return this._es !== null ? this._es : (this.parent && this.parent.getEasing()) || null;
94 };
95 /**
96 * Set the easing for this animation.
97 */
98 Animation.prototype.easing = function (name) {
99 this._es = name;
100 return this;
101 };
102 /**
103 * Set the easing for this reversed animation.
104 */
105 Animation.prototype.easingReverse = function (name) {
106 this._rvEs = name;
107 return this;
108 };
109 /**
110 * Add the "from" value for a specific property.
111 */
112 Animation.prototype.from = function (prop, val) {
113 this._addProp('from', prop, val);
114 return this;
115 };
116 /**
117 * Add the "to" value for a specific property.
118 */
119 Animation.prototype.to = function (prop, val, clearProperyAfterTransition) {
120 var fx = this._addProp('to', prop, val);
121 if (clearProperyAfterTransition) {
122 // if this effect is a transform then clear the transform effect
123 // otherwise just clear the actual property
124 this.afterClearStyles([fx.trans ? this.plt.Css.transform : prop]);
125 }
126 return this;
127 };
128 /**
129 * Shortcut to add both the "from" and "to" for the same property.
130 */
131 Animation.prototype.fromTo = function (prop, fromVal, toVal, clearProperyAfterTransition) {
132 return this.from(prop, fromVal).to(prop, toVal, clearProperyAfterTransition);
133 };
134 /**
135 * @hidden
136 * NO DOM
137 */
138 Animation.prototype._getProp = function (name) {
139 if (this._fx) {
140 return this._fx.find(function (prop) { return prop.name === name; });
141 }
142 else {
143 this._fx = [];
144 }
145 return null;
146 };
147 Animation.prototype._addProp = function (state, prop, val) {
148 var fxProp = this._getProp(prop);
149 if (!fxProp) {
150 // first time we've see this EffectProperty
151 var shouldTrans = (ANIMATION_TRANSFORMS[prop] === 1);
152 fxProp = {
153 name: prop,
154 trans: shouldTrans,
155 // add the will-change property for transforms or opacity
156 wc: (shouldTrans ? this.plt.Css.transform : prop)
157 };
158 this._fx.push(fxProp);
159 }
160 // add from/to EffectState to the EffectProperty
161 var fxState = {
162 val: val,
163 num: null,
164 unit: '',
165 };
166 fxProp[state] = fxState;
167 if (typeof val === 'string' && val.indexOf(' ') < 0) {
168 var r = val.match(ANIMATION_CSS_VALUE_REGEX);
169 var num = parseFloat(r[1]);
170 if (!isNaN(num)) {
171 fxState.num = num;
172 }
173 fxState.unit = (r[0] !== r[2] ? r[2] : '');
174 }
175 else if (typeof val === 'number') {
176 fxState.num = val;
177 }
178 return fxProp;
179 };
180 /**
181 * Add CSS class to this animation's elements
182 * before the animation begins.
183 */
184 Animation.prototype.beforeAddClass = function (className) {
185 (this._bfAdd = this._bfAdd || []).push(className);
186 return this;
187 };
188 /**
189 * Remove CSS class from this animation's elements
190 * before the animation begins.
191 */
192 Animation.prototype.beforeRemoveClass = function (className) {
193 (this._bfRm = this._bfRm || []).push(className);
194 return this;
195 };
196 /**
197 * Set CSS inline styles to this animation's elements
198 * before the animation begins.
199 */
200 Animation.prototype.beforeStyles = function (styles) {
201 this._bfSty = styles;
202 return this;
203 };
204 /**
205 * Clear CSS inline styles from this animation's elements
206 * before the animation begins.
207 */
208 Animation.prototype.beforeClearStyles = function (propertyNames) {
209 this._bfSty = this._bfSty || {};
210 for (var i = 0; i < propertyNames.length; i++) {
211 this._bfSty[propertyNames[i]] = '';
212 }
213 return this;
214 };
215 /**
216 * Add a function which contains DOM reads, which will run
217 * before the animation begins.
218 */
219 Animation.prototype.beforeAddRead = function (domReadFn) {
220 (this._rdFn = this._rdFn || []).push(domReadFn);
221 return this;
222 };
223 /**
224 * Add a function which contains DOM writes, which will run
225 * before the animation begins.
226 */
227 Animation.prototype.beforeAddWrite = function (domWriteFn) {
228 (this._wrFn = this._wrFn || []).push(domWriteFn);
229 return this;
230 };
231 /**
232 * Add CSS class to this animation's elements
233 * after the animation finishes.
234 */
235 Animation.prototype.afterAddClass = function (className) {
236 (this._afAdd = this._afAdd || []).push(className);
237 return this;
238 };
239 /**
240 * Remove CSS class from this animation's elements
241 * after the animation finishes.
242 */
243 Animation.prototype.afterRemoveClass = function (className) {
244 (this._afRm = this._afRm || []).push(className);
245 return this;
246 };
247 /**
248 * Set CSS inline styles to this animation's elements
249 * after the animation finishes.
250 */
251 Animation.prototype.afterStyles = function (styles) {
252 this._afSty = styles;
253 return this;
254 };
255 /**
256 * Clear CSS inline styles from this animation's elements
257 * after the animation finishes.
258 */
259 Animation.prototype.afterClearStyles = function (propertyNames) {
260 this._afSty = this._afSty || {};
261 for (var i = 0; i < propertyNames.length; i++) {
262 this._afSty[propertyNames[i]] = '';
263 }
264 return this;
265 };
266 /**
267 * Play the animation.
268 */
269 Animation.prototype.play = function (opts) {
270 var _this = this;
271 // If the animation was already invalidated (it did finish), do nothing
272 if (!this.plt) {
273 return;
274 }
275 // this is the top level animation and is in full control
276 // of when the async play() should actually kick off
277 // if there is no duration then it'll set the TO property immediately
278 // if there is a duration, then it'll stage all animations at the
279 // FROM property and transition duration, wait a few frames, then
280 // kick off the animation by setting the TO property for each animation
281 this._isAsync = this._hasDuration(opts);
282 // ensure all past transition end events have been cleared
283 this._clearAsync();
284 // recursively kicks off the correct progress step for each child animation
285 // ******** DOM WRITE ****************
286 this._playInit(opts);
287 // doubling up RAFs since this animation was probably triggered
288 // from an input event, and just having one RAF would have this code
289 // run within the same frame as the triggering input event, and the
290 // input event probably already did way too much work for one frame
291 this.plt.raf(function () {
292 _this.plt.raf(_this._playDomInspect.bind(_this, opts));
293 });
294 };
295 Animation.prototype.syncPlay = function () {
296 // If the animation was already invalidated (it did finish), do nothing
297 if (!this.plt) {
298 return;
299 }
300 var opts = { duration: 0 };
301 this._isAsync = false;
302 this._clearAsync();
303 this._playInit(opts);
304 this._playDomInspect(opts);
305 };
306 /**
307 * @hidden
308 * DOM WRITE
309 * RECURSION
310 */
311 Animation.prototype._playInit = function (opts) {
312 // always default that an animation does not tween
313 // a tween requires that an Animation class has an element
314 // and that it has at least one FROM/TO effect
315 // and that the FROM/TO effect can tween numeric values
316 this._twn = false;
317 this.isPlaying = true;
318 this.hasCompleted = false;
319 this._hasDur = (this.getDuration(opts) > ANIMATION_DURATION_MIN);
320 var children = this._c;
321 for (var i = 0; i < this._cL; i++) {
322 // ******** DOM WRITE ****************
323 children[i]._playInit(opts);
324 }
325 if (this._hasDur) {
326 // if there is a duration then we want to start at step 0
327 // ******** DOM WRITE ****************
328 this._progress(0);
329 // add the will-change properties
330 // ******** DOM WRITE ****************
331 this._willChg(true);
332 }
333 };
334 /**
335 * @hidden
336 * DOM WRITE
337 * NO RECURSION
338 * ROOT ANIMATION
339 */
340 Animation.prototype._playDomInspect = function (opts) {
341 // fire off all the "before" function that have DOM READS in them
342 // elements will be in the DOM, however visibily hidden
343 // so we can read their dimensions if need be
344 // ******** DOM READ ****************
345 // ******** DOM WRITE ****************
346 this._beforeAnimation();
347 // for the root animation only
348 // set the async TRANSITION END event
349 // and run onFinishes when the transition ends
350 var dur = this.getDuration(opts);
351 if (this._isAsync) {
352 this._asyncEnd(dur, true);
353 }
354 // ******** DOM WRITE ****************
355 this._playProgress(opts);
356 if (this._isAsync && this.plt) {
357 // this animation has a duration so we need another RAF
358 // for the CSS TRANSITION properties to kick in
359 this.plt.raf(this._playToStep.bind(this, 1));
360 }
361 };
362 /**
363 * @hidden
364 * DOM WRITE
365 * RECURSION
366 */
367 Animation.prototype._playProgress = function (opts) {
368 var children = this._c;
369 for (var i = 0; i < this._cL; i++) {
370 // ******** DOM WRITE ****************
371 children[i]._playProgress(opts);
372 }
373 if (this._hasDur) {
374 // set the CSS TRANSITION duration/easing
375 // ******** DOM WRITE ****************
376 this._setTrans(this.getDuration(opts), false);
377 }
378 else {
379 // this animation does not have a duration, so it should not animate
380 // just go straight to the TO properties and call it done
381 // ******** DOM WRITE ****************
382 this._progress(1);
383 // since there was no animation, immediately run the after
384 // ******** DOM WRITE ****************
385 this._setAfterStyles();
386 // this animation has no duration, so it has finished
387 // other animations could still be running
388 this._didFinish(true);
389 }
390 };
391 /**
392 * @hidden
393 * DOM WRITE
394 * RECURSION
395 */
396 Animation.prototype._playToStep = function (stepValue) {
397 var children = this._c;
398 for (var i = 0; i < this._cL; i++) {
399 // ******** DOM WRITE ****************
400 children[i]._playToStep(stepValue);
401 }
402 if (this._hasDur) {
403 // browser had some time to render everything in place
404 // and the transition duration/easing is set
405 // now set the TO properties which will trigger the transition to begin
406 // ******** DOM WRITE ****************
407 this._progress(stepValue);
408 }
409 };
410 /**
411 * @hidden
412 * DOM WRITE
413 * NO RECURSION
414 * ROOT ANIMATION
415 */
416 Animation.prototype._asyncEnd = function (dur, shouldComplete) {
417 (void 0) /* assert */;
418 (void 0) /* assert */;
419 (void 0) /* assert */;
420 var self = this;
421 function onTransitionEnd() {
422 // congrats! a successful transition completed!
423 // ensure transition end events and timeouts have been cleared
424 self._clearAsync();
425 // ******** DOM WRITE ****************
426 self._playEnd();
427 // transition finished
428 self._didFinishAll(shouldComplete, true, false);
429 }
430 function onTransitionFallback() {
431 (void 0) /* console.debug */;
432 // oh noz! the transition end event didn't fire in time!
433 // instead the fallback timer when first
434 // if all goes well this fallback should never fire
435 // clear the other async end events from firing
436 self._tm = undefined;
437 self._clearAsync();
438 // set the after styles
439 // ******** DOM WRITE ****************
440 self._playEnd(shouldComplete ? 1 : 0);
441 // transition finished
442 self._didFinishAll(shouldComplete, true, false);
443 }
444 // set the TRANSITION END event on one of the transition elements
445 self._unrgTrns = this.plt.transitionEnd(self._transEl(), onTransitionEnd, false);
446 // set a fallback timeout if the transition end event never fires, or is too slow
447 // transition end fallback: (animation duration + XXms)
448 self._tm = self.plt.timeout(onTransitionFallback, (dur + ANIMATION_TRANSITION_END_FALLBACK_PADDING_MS));
449 };
450 /**
451 * @hidden
452 * DOM WRITE
453 * RECURSION
454 */
455 Animation.prototype._playEnd = function (stepValue) {
456 var children = this._c;
457 for (var i = 0; i < this._cL; i++) {
458 // ******** DOM WRITE ****************
459 children[i]._playEnd(stepValue);
460 }
461 if (this._hasDur) {
462 if (isDefined(stepValue)) {
463 // too late to have a smooth animation, just finish it
464 // ******** DOM WRITE ****************
465 this._setTrans(0, true);
466 // ensure the ending progress step gets rendered
467 // ******** DOM WRITE ****************
468 this._progress(stepValue);
469 }
470 // set the after styles
471 // ******** DOM WRITE ****************
472 this._setAfterStyles();
473 // remove the will-change properties
474 // ******** DOM WRITE ****************
475 this._willChg(false);
476 }
477 };
478 /**
479 * @hidden
480 * NO DOM
481 * RECURSION
482 */
483 Animation.prototype._hasDuration = function (opts) {
484 if (this.getDuration(opts) > ANIMATION_DURATION_MIN) {
485 return true;
486 }
487 var children = this._c;
488 for (var i = 0; i < this._cL; i++) {
489 if (children[i]._hasDuration(opts)) {
490 return true;
491 }
492 }
493 return false;
494 };
495 /**
496 * @hidden
497 * NO DOM
498 * RECURSION
499 */
500 Animation.prototype._hasDomReads = function () {
501 if (this._rdFn && this._rdFn.length) {
502 return true;
503 }
504 var children = this._c;
505 for (var i = 0; i < this._cL; i++) {
506 if (children[i]._hasDomReads()) {
507 return true;
508 }
509 }
510 return false;
511 };
512 /**
513 * Immediately stop at the end of the animation.
514 */
515 Animation.prototype.stop = function (stepValue) {
516 if (stepValue === void 0) { stepValue = 1; }
517 // ensure all past transition end events have been cleared
518 this._clearAsync();
519 this._hasDur = true;
520 this._playEnd(stepValue);
521 };
522 /**
523 * @hidden
524 * NO DOM
525 * NO RECURSION
526 */
527 Animation.prototype._clearAsync = function () {
528 this._unrgTrns && this._unrgTrns();
529 this._tm && clearTimeout(this._tm);
530 this._tm = this._unrgTrns = undefined;
531 };
532 /**
533 * @hidden
534 * DOM WRITE
535 * NO RECURSION
536 */
537 Animation.prototype._progress = function (stepValue) {
538 // bread 'n butter
539 var val;
540 var effects = this._fx;
541 var nuElements = this._eL;
542 if (!effects || !nuElements) {
543 return;
544 }
545 // flip the number if we're going in reverse
546 if (this._rv) {
547 stepValue = ((stepValue * -1) + 1);
548 }
549 var i, j;
550 var finalTransform = '';
551 var elements = this._e;
552 for (i = 0; i < effects.length; i++) {
553 var fx = effects[i];
554 if (fx.from && fx.to) {
555 var fromNum = fx.from.num;
556 var toNum = fx.to.num;
557 var tweenEffect = (fromNum !== toNum);
558 (void 0) /* assert */;
559 if (tweenEffect) {
560 this._twn = true;
561 }
562 if (stepValue === 0) {
563 // FROM
564 val = fx.from.val;
565 }
566 else if (stepValue === 1) {
567 // TO
568 val = fx.to.val;
569 }
570 else if (tweenEffect) {
571 // EVERYTHING IN BETWEEN
572 var valNum = (((toNum - fromNum) * stepValue) + fromNum);
573 var unit = fx.to.unit;
574 if (unit === 'px') {
575 valNum = Math.round(valNum);
576 }
577 val = valNum + unit;
578 }
579 if (val !== null) {
580 var prop = fx.name;
581 if (fx.trans) {
582 finalTransform += prop + '(' + val + ') ';
583 }
584 else {
585 for (j = 0; j < nuElements; j++) {
586 // ******** DOM WRITE ****************
587 elements[j].style[prop] = val;
588 }
589 }
590 }
591 }
592 }
593 // place all transforms on the same property
594 if (finalTransform.length) {
595 if (!this._rv && stepValue !== 1 || this._rv && stepValue !== 0) {
596 finalTransform += 'translateZ(0px)';
597 }
598 var cssTransform = this.plt.Css.transform;
599 for (i = 0; i < elements.length; i++) {
600 // ******** DOM WRITE ****************
601 elements[i].style[cssTransform] = finalTransform;
602 }
603 }
604 };
605 /**
606 * @hidden
607 * DOM WRITE
608 * NO RECURSION
609 */
610 Animation.prototype._setTrans = function (dur, forcedLinearEasing) {
611 // Transition is not enabled if there are not effects
612 if (!this._fx) {
613 return;
614 }
615 // set the TRANSITION properties inline on the element
616 var elements = this._e;
617 var easing = (forcedLinearEasing ? 'linear' : this.getEasing());
618 var durString = dur + 'ms';
619 var Css = this.plt.Css;
620 var cssTransform = Css.transition;
621 var cssTransitionDuration = Css.transitionDuration;
622 var cssTransitionTimingFn = Css.transitionTimingFn;
623 var eleStyle;
624 for (var i = 0; i < this._eL; i++) {
625 eleStyle = elements[i].style;
626 if (dur > 0) {
627 // ******** DOM WRITE ****************
628 eleStyle[cssTransform] = '';
629 eleStyle[cssTransitionDuration] = durString;
630 // each animation can have a different easing
631 if (easing) {
632 // ******** DOM WRITE ****************
633 eleStyle[cssTransitionTimingFn] = easing;
634 }
635 }
636 else {
637 eleStyle[cssTransform] = 'none';
638 }
639 }
640 };
641 /**
642 * @hidden
643 * DOM READ
644 * DOM WRITE
645 * RECURSION
646 */
647 Animation.prototype._beforeAnimation = function () {
648 // fire off all the "before" function that have DOM READS in them
649 // elements will be in the DOM, however visibily hidden
650 // so we can read their dimensions if need be
651 // ******** DOM READ ****************
652 this._fireBeforeReadFunc();
653 // ******** DOM READS ABOVE / DOM WRITES BELOW ****************
654 // fire off all the "before" function that have DOM WRITES in them
655 // ******** DOM WRITE ****************
656 this._fireBeforeWriteFunc();
657 // stage all of the before css classes and inline styles
658 // ******** DOM WRITE ****************
659 this._setBeforeStyles();
660 };
661 /**
662 * @hidden
663 * DOM WRITE
664 * RECURSION
665 */
666 Animation.prototype._setBeforeStyles = function () {
667 var i, j;
668 var children = this._c;
669 for (i = 0; i < this._cL; i++) {
670 children[i]._setBeforeStyles();
671 }
672 // before the animations have started
673 // only set before styles if animation is not reversed
674 if (this._rv) {
675 return;
676 }
677 var addClasses = this._bfAdd;
678 var removeClasses = this._bfRm;
679 var ele;
680 var eleClassList;
681 var prop;
682 for (i = 0; i < this._eL; i++) {
683 ele = this._e[i];
684 eleClassList = ele.classList;
685 // css classes to add before the animation
686 if (addClasses) {
687 for (j = 0; j < addClasses.length; j++) {
688 // ******** DOM WRITE ****************
689 eleClassList.add(addClasses[j]);
690 }
691 }
692 // css classes to remove before the animation
693 if (removeClasses) {
694 for (j = 0; j < removeClasses.length; j++) {
695 // ******** DOM WRITE ****************
696 eleClassList.remove(removeClasses[j]);
697 }
698 }
699 // inline styles to add before the animation
700 if (this._bfSty) {
701 for (prop in this._bfSty) {
702 // ******** DOM WRITE ****************
703 ele.style[prop] = this._bfSty[prop];
704 }
705 }
706 }
707 };
708 /**
709 * @hidden
710 * DOM READ
711 * RECURSION
712 */
713 Animation.prototype._fireBeforeReadFunc = function () {
714 var children = this._c;
715 for (var i = 0; i < this._cL; i++) {
716 // ******** DOM READ ****************
717 children[i]._fireBeforeReadFunc();
718 }
719 var readFunctions = this._rdFn;
720 if (readFunctions) {
721 for (var i = 0; i < readFunctions.length; i++) {
722 // ******** DOM READ ****************
723 readFunctions[i]();
724 }
725 }
726 };
727 /**
728 * @hidden
729 * DOM WRITE
730 * RECURSION
731 */
732 Animation.prototype._fireBeforeWriteFunc = function () {
733 var children = this._c;
734 for (var i = 0; i < this._cL; i++) {
735 // ******** DOM WRITE ****************
736 children[i]._fireBeforeWriteFunc();
737 }
738 var writeFunctions = this._wrFn;
739 if (this._wrFn) {
740 for (var i = 0; i < writeFunctions.length; i++) {
741 // ******** DOM WRITE ****************
742 writeFunctions[i]();
743 }
744 }
745 };
746 /**
747 * @hidden
748 * DOM WRITE
749 */
750 Animation.prototype._setAfterStyles = function () {
751 var i, j;
752 var ele;
753 var eleClassList;
754 var elements = this._e;
755 for (i = 0; i < this._eL; i++) {
756 ele = elements[i];
757 eleClassList = ele.classList;
758 // remove the transition duration/easing
759 // ******** DOM WRITE ****************
760 ele.style[this.plt.Css.transitionDuration] = ele.style[this.plt.Css.transitionTimingFn] = '';
761 if (this._rv) {
762 // finished in reverse direction
763 // css classes that were added before the animation should be removed
764 if (this._bfAdd) {
765 for (j = 0; j < this._bfAdd.length; j++) {
766 // ******** DOM WRITE ****************
767 eleClassList.remove(this._bfAdd[j]);
768 }
769 }
770 // css classes that were removed before the animation should be added
771 if (this._bfRm) {
772 for (j = 0; j < this._bfRm.length; j++) {
773 // ******** DOM WRITE ****************
774 eleClassList.add(this._bfRm[j]);
775 }
776 }
777 // inline styles that were added before the animation should be removed
778 if (this._bfSty) {
779 for (var prop in this._bfSty) {
780 // ******** DOM WRITE ****************
781 ele.style[prop] = '';
782 }
783 }
784 }
785 else {
786 // finished in forward direction
787 // css classes to add after the animation
788 if (this._afAdd) {
789 for (j = 0; j < this._afAdd.length; j++) {
790 // ******** DOM WRITE ****************
791 eleClassList.add(this._afAdd[j]);
792 }
793 }
794 // css classes to remove after the animation
795 if (this._afRm) {
796 for (j = 0; j < this._afRm.length; j++) {
797 // ******** DOM WRITE ****************
798 eleClassList.remove(this._afRm[j]);
799 }
800 }
801 // inline styles to add after the animation
802 if (this._afSty) {
803 for (var prop in this._afSty) {
804 // ******** DOM WRITE ****************
805 ele.style[prop] = this._afSty[prop];
806 }
807 }
808 }
809 }
810 };
811 /**
812 * @hidden
813 * DOM WRITE
814 * NO RECURSION
815 */
816 Animation.prototype._willChg = function (addWillChange) {
817 var wc;
818 var effects = this._fx;
819 var willChange;
820 if (addWillChange && effects) {
821 wc = [];
822 for (var i = 0; i < effects.length; i++) {
823 var propWC = effects[i].wc;
824 if (propWC === 'webkitTransform') {
825 wc.push('transform', '-webkit-transform');
826 }
827 else {
828 wc.push(propWC);
829 }
830 }
831 willChange = wc.join(',');
832 }
833 else {
834 willChange = '';
835 }
836 for (var i = 0; i < this._eL; i++) {
837 // ******** DOM WRITE ****************
838 this._e[i].style.willChange = willChange;
839 }
840 };
841 /**
842 * Start the animation with a user controlled progress.
843 */
844 Animation.prototype.progressStart = function () {
845 // ensure all past transition end events have been cleared
846 this._clearAsync();
847 // ******** DOM READ/WRITE ****************
848 this._beforeAnimation();
849 // ******** DOM WRITE ****************
850 this._progressStart();
851 };
852 /**
853 * @hidden
854 * DOM WRITE
855 * RECURSION
856 */
857 Animation.prototype._progressStart = function () {
858 var children = this._c;
859 for (var i = 0; i < this._cL; i++) {
860 // ******** DOM WRITE ****************
861 children[i]._progressStart();
862 }
863 // force no duration, linear easing
864 // ******** DOM WRITE ****************
865 this._setTrans(0, true);
866 // ******** DOM WRITE ****************
867 this._willChg(true);
868 };
869 /**
870 * Set the progress step for this animation.
871 * progressStep() is not debounced, so it should not be called faster than 60FPS.
872 */
873 Animation.prototype.progressStep = function (stepValue) {
874 // only update if the last update was more than 16ms ago
875 stepValue = Math.min(1, Math.max(0, stepValue));
876 var children = this._c;
877 for (var i = 0; i < this._cL; i++) {
878 // ******** DOM WRITE ****************
879 children[i].progressStep(stepValue);
880 }
881 if (this._rv) {
882 // if the animation is going in reverse then
883 // flip the step value: 0 becomes 1, 1 becomes 0
884 stepValue = ((stepValue * -1) + 1);
885 }
886 // ******** DOM WRITE ****************
887 this._progress(stepValue);
888 };
889 /**
890 * End the progress animation.
891 */
892 Animation.prototype.progressEnd = function (shouldComplete, currentStepValue, dur) {
893 if (dur === void 0) { dur = -1; }
894 (void 0) /* console.debug */;
895 if (this._rv) {
896 // if the animation is going in reverse then
897 // flip the step value: 0 becomes 1, 1 becomes 0
898 currentStepValue = ((currentStepValue * -1) + 1);
899 }
900 var stepValue = shouldComplete ? 1 : 0;
901 var diff = Math.abs(currentStepValue - stepValue);
902 if (diff < 0.05) {
903 dur = 0;
904 }
905 else if (dur < 0) {
906 dur = this._dur;
907 }
908 this._isAsync = (dur > 30);
909 this._progressEnd(shouldComplete, stepValue, dur, this._isAsync);
910 if (this._isAsync) {
911 // for the root animation only
912 // set the async TRANSITION END event
913 // and run onFinishes when the transition ends
914 // ******** DOM WRITE ****************
915 this._asyncEnd(dur, shouldComplete);
916 // this animation has a duration so we need another RAF
917 // for the CSS TRANSITION properties to kick in
918 this.plt && this.plt.raf(this._playToStep.bind(this, stepValue));
919 }
920 };
921 /**
922 * @hidden
923 * DOM WRITE
924 * RECURSION
925 */
926 Animation.prototype._progressEnd = function (shouldComplete, stepValue, dur, isAsync) {
927 var children = this._c;
928 for (var i = 0; i < this._cL; i++) {
929 // ******** DOM WRITE ****************
930 children[i]._progressEnd(shouldComplete, stepValue, dur, isAsync);
931 }
932 if (!isAsync) {
933 // stop immediately
934 // set all the animations to their final position
935 // ******** DOM WRITE ****************
936 this._progress(stepValue);
937 this._willChg(false);
938 this._setAfterStyles();
939 this._didFinish(shouldComplete);
940 }
941 else {
942 // animate it back to it's ending position
943 this.isPlaying = true;
944 this.hasCompleted = false;
945 this._hasDur = true;
946 // ******** DOM WRITE ****************
947 this._willChg(true);
948 this._setTrans(dur, false);
949 }
950 };
951 /**
952 * Add a callback to fire when the animation has finished.
953 */
954 Animation.prototype.onFinish = function (callback, onceTimeCallback, clearOnFinishCallacks) {
955 if (onceTimeCallback === void 0) { onceTimeCallback = false; }
956 if (clearOnFinishCallacks === void 0) { clearOnFinishCallacks = false; }
957 if (clearOnFinishCallacks) {
958 this._fFn = this._fOneFn = undefined;
959 }
960 if (onceTimeCallback) {
961 this._fOneFn = this._fOneFn || [];
962 this._fOneFn.push(callback);
963 }
964 else {
965 this._fFn = this._fFn || [];
966 this._fFn.push(callback);
967 }
968 return this;
969 };
970 /**
971 * @hidden
972 * NO DOM
973 * RECURSION
974 */
975 Animation.prototype._didFinishAll = function (hasCompleted, finishAsyncAnimations, finishNoDurationAnimations) {
976 var children = this._c;
977 for (var i = 0; i < this._cL; i++) {
978 children[i]._didFinishAll(hasCompleted, finishAsyncAnimations, finishNoDurationAnimations);
979 }
980 if (finishAsyncAnimations && this._isAsync || finishNoDurationAnimations && !this._isAsync) {
981 this._didFinish(hasCompleted);
982 }
983 };
984 /**
985 * @hidden
986 * NO RECURSION
987 */
988 Animation.prototype._didFinish = function (hasCompleted) {
989 this.isPlaying = false;
990 this.hasCompleted = hasCompleted;
991 if (this._fFn) {
992 // run all finish callbacks
993 for (var i = 0; i < this._fFn.length; i++) {
994 this._fFn[i](this);
995 }
996 }
997 if (this._fOneFn) {
998 // run all "onetime" finish callbacks
999 for (var i = 0; i < this._fOneFn.length; i++) {
1000 this._fOneFn[i](this);
1001 }
1002 this._fOneFn.length = 0;
1003 }
1004 };
1005 /**
1006 * Reverse the animation.
1007 */
1008 Animation.prototype.reverse = function (shouldReverse) {
1009 if (shouldReverse === void 0) { shouldReverse = true; }
1010 var children = this._c;
1011 for (var i = 0; i < this._cL; i++) {
1012 children[i].reverse(shouldReverse);
1013 }
1014 this._rv = shouldReverse;
1015 return this;
1016 };
1017 /**
1018 * Recursively destroy this animation and all child animations.
1019 */
1020 Animation.prototype.destroy = function () {
1021 var children = this._c;
1022 for (var i = 0; i < this._cL; i++) {
1023 children[i].destroy();
1024 }
1025 this._clearAsync();
1026 this.parent = this.plt = this._e = this._rdFn = this._wrFn = null;
1027 if (this._c) {
1028 this._c.length = this._cL = 0;
1029 }
1030 if (this._fFn) {
1031 this._fFn.length = 0;
1032 }
1033 if (this._fOneFn) {
1034 this._fOneFn.length = 0;
1035 }
1036 };
1037 /**
1038 * @hidden
1039 * NO DOM
1040 */
1041 Animation.prototype._transEl = function () {
1042 // get the lowest level element that has an Animation
1043 var targetEl;
1044 for (var i = 0; i < this._cL; i++) {
1045 targetEl = this._c[i]._transEl();
1046 if (targetEl) {
1047 return targetEl;
1048 }
1049 }
1050 return (this._twn && this._hasDur && this._eL ? this._e[0] : null);
1051 };
1052 return Animation;
1053}());
1054export { Animation };
1055var ANIMATION_TRANSFORMS = {
1056 'translateX': 1,
1057 'translateY': 1,
1058 'translateZ': 1,
1059 'scale': 1,
1060 'scaleX': 1,
1061 'scaleY': 1,
1062 'scaleZ': 1,
1063 'rotate': 1,
1064 'rotateX': 1,
1065 'rotateY': 1,
1066 'rotateZ': 1,
1067 'skewX': 1,
1068 'skewY': 1,
1069 'perspective': 1
1070};
1071var ANIMATION_CSS_VALUE_REGEX = /(^-?\d*\.?\d*)(.*)/;
1072var ANIMATION_DURATION_MIN = 32;
1073var ANIMATION_TRANSITION_END_FALLBACK_PADDING_MS = 400;
1074//# sourceMappingURL=animation.js.map
\No newline at end of file