1 | import { isDefined } from '../util/util';
|
2 | /**
|
3 | * @hidden
|
4 | */
|
5 | var 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 | }());
|
1054 | export { Animation };
|
1055 | var 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 | };
|
1071 | var ANIMATION_CSS_VALUE_REGEX = /(^-?\d*\.?\d*)(.*)/;
|
1072 | var ANIMATION_DURATION_MIN = 32;
|
1073 | var ANIMATION_TRANSITION_END_FALLBACK_PADDING_MS = 400;
|
1074 | //# sourceMappingURL=animation.js.map |
\ | No newline at end of file |