Files
2015-05-19 21:59:49 -05:00

268 lines
5.6 KiB
JavaScript

import * as util from 'ionic/util/util';
export class Animation {
constructor(el) {
this._el = [];
this._parent = null;
this._children = [];
this._players = [];
this._from = null;
this._to = null;
this._duration = null;
this._easing = null;
this._beforeAddCls = [];
this._beforeRmvCls = [];
this._afterAddCls = [];
this._afterRmvCls = [];
this.elements(el);
}
elements(el) {
if (el) {
if (typeof el === 'string') {
el = document.querySelectorAll(ele);
}
if (el.length) {
for (let i = 0; i < el.length; i++) {
this._el.push(el[i]);
}
} else if (el.nodeType) {
this._el.push(el);
}
}
return this;
}
parent(parentAnimation) {
this._parent = parentAnimation;
return this;
}
addChild(childAnimation) {
if (childAnimation) {
childAnimation.parent(this);
this._children.push(childAnimation);
}
return this;
}
children(arr) {
arr = Array.isArray(arr) ? arr : arguments;
for (let i = 0; i < arr.length; i++) {
this.addChild(arr[i]);
}
return this;
}
duration(value) {
if (arguments.length) {
this._duration = value;
return this;
}
return this._duration || (this._parent && this._parent.duration());
}
easing(value) {
if (arguments.length) {
this._easing = value;
return this;
}
return this._easing || (this._parent && this._parent.easing());
}
from(property, value) {
if (!this._from) {
this._from = {};
}
this._from[property] = value;
return this;
}
to(property, value) {
if (!this._to) {
this._to = {};
}
this._to[property] = value;
return this;
}
get beforePlay() {
return {
addClass: (className) => {
this._beforeAddCls.push(className);
return this;
},
removeClass: (className) => {
this._beforeRmvCls.push(className);
return this;
}
}
}
get afterFinish() {
return {
addClass: (className) => {
this._afterAddCls.push(className);
return this;
},
removeClass: (className) => {
this._afterRmvCls.push(className);
return this;
}
}
}
play() {
let promises = [];
for (let i = 0; i < this._children.length; i++) {
promises.push( this._children[i].play() );
}
if (!this._to) {
// probably just add/removing classes, create bogus transition
this._from = this._to = {'opacity': 1};
}
if (!this._players.length) {
for (let i = 0; i < this._el.length; i++) {
var ele = this._el[i];
for (let j = 0; j < this._beforeAddCls.length; j++) {
ele.classList.add(this._beforeAddCls[j]);
}
for (let j = 0; j < this._beforeRmvCls.length; j++) {
ele.classList.remove(this._beforeRmvCls[j]);
}
var player = new Animate(ele, this._from, this._to, this.duration(), this.easing());
this._players.push(player);
promises.push(player.promise);
}
} else {
for (let i = 0; i < this._players.length; i++) {
this._players[i].play();
}
}
var promise = Promise.all(promises);
promise.then(() => {
for (let i = 0; i < this._el.length; i++) {
var ele = this._el[i];
for (let j = 0; j < this._afterAddCls.length; j++) {
ele.classList.add(this._afterAddCls[j]);
}
for (let j = 0; j < this._afterRmvCls.length; j++) {
ele.classList.remove(this._afterRmvCls[j]);
}
}
});
return promise;
}
pause() {
for (let i = 0; i < this._children.length; i++) {
this._children[i].pause();
}
for (let i = 0; i < this._players.length; i++) {
this._players[i].pause();
}
}
progress(value) {
for (let i = 0; i < this._children.length; i++) {
this._children[i].progress(value);
}
if (!this._players.length) {
this.play();
this.pause();
}
for (let i = 0; i < this._players.length; i++) {
this._players[i].progress(value);
}
}
}
class Animate {
constructor(ele, fromEffect, toEffect, duration, easing) {
// https://w3c.github.io/web-animations/
// not using the direct API methods because they're still in flux
// however, element.animate() seems locked in and uses the latest
// and correct API methods under the hood, so really doesn't matter
// fromEffect must be manually computed if it wasn't provided
// https://github.com/web-animations/web-animations-js/issues/14
fromEffect = fromEffect || {};
let style = null;
for (let prop in toEffect) {
if (util.isBlank(fromEffect[prop])) {
style = style || window.getComputedStyle(ele);
fromEffect[prop] = style[prop];
}
}
this._duration = duration;
this._easing = easing;
this.player = ele.animate([fromEffect, toEffect], {
duration: duration,
easing: easing,
fill: 'both'
});
this.promise = new Promise(resolve => {
this.player.onfinish = () => {
resolve();
};
});
}
play() {
this.player.play();
}
pause() {
this.player.pause();
}
progress(value) {
let player = this.player;
// passed a number between 0 and 1
value = Math.max(0, Math.min(1, parseFloat(value)));
if (value === 1) {
player.currentTime = (this._duration * 0.9999);
player.play();
return;
}
if (player.playState !== 'paused') {
player.pause();
}
player.currentTime = (this._duration * value);
}
}