Files
NativeScript/ui/animation/keyframe-animation.ts
Tsvetan Raikov 073cc94926 implemented CSS animations
fixing animation tests
2016-03-25 15:26:48 +02:00

197 lines
7.3 KiB
TypeScript

import definition = require("ui/animation/keyframe-animation");
import view = require("ui/core/view");
import enums = require("ui/enums");
import style = require("ui/styling/style");
export class KeyframeDeclaration implements definition.KeyframeDeclaration {
public property: string;
public value: any;
}
export class KeyframeInfo implements definition.KeyframeInfo {
public duration: number;
public curve: any;
public declarations: Array<KeyframeDeclaration>;
}
export class KeyframeAnimationInfo implements definition.KeyframeAnimationInfo {
public name: string = "";
public duration: number = 0.3;
public delay: number = 0;
public iterations: number = 1;
public curve: any = enums.AnimationCurve.ease;
public isForwards: boolean = false;
public isReverse: boolean = false;
public keyframes: Array<KeyframeInfo>;
}
export class KeyframeAnimation {
public animations: Array<Object>;
public delay: number = 0;
public iterations: number = 1;
private _resolve;
private _reject;
private _isPlaying: boolean;
private _isForwards: boolean;
public static keyframeAnimationFromInfo(info: KeyframeAnimationInfo, valueSourceModifier: number) {
let animations = new Array<Object>();
let length = info.keyframes.length;
let startDuration = 0;
if (info.isReverse) {
for (let index = length - 1; index >= 0; index --) {
let keyframe = info.keyframes[index];
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration, valueSourceModifier);
}
}
else {
for (let index = 0; index < length; index ++) {
let keyframe = info.keyframes[index];
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration, valueSourceModifier);
}
for (let index = length - 1; index > 0; index --) {
let a1 = animations[index];
let a2 = animations[index - 1];
if (a2["curve"] !== undefined) {
a1["curve"] = a2["curve"];
a2["curve"] = undefined;
}
}
}
for (let index = 1; index < length; index++) {
let a = animations[index];
if (a["curve"] === undefined) {
a["curve"] = info.curve;
}
}
let animation: KeyframeAnimation = new KeyframeAnimation();
animation.delay = info.delay;
animation.iterations = info.iterations;
animation.animations = animations;
animation._isForwards = info.isForwards;
return animation;
}
private static parseKeyframe(info: KeyframeAnimationInfo, keyframe: KeyframeInfo, animations: Array<Object>, startDuration: number, valueSourceModifier: number): number {
let animation = {};
for (let declaration of keyframe.declarations) {
animation[declaration.property] = declaration.value;
}
let duration = keyframe.duration;
if (duration === 0) {
duration = 0.01;
}
else {
duration = (info.duration * duration) - startDuration;
startDuration += duration;
}
animation["duration"] = info.isReverse ? info.duration - duration : duration;
animation["curve"] = keyframe.curve;
animation["forceLayer"] = true;
animation["valueSource"] = valueSourceModifier;
animations.push(animation);
return startDuration;
}
public get isPlaying(): boolean {
return this._isPlaying;
}
public play(view: view.View): Promise<void> {
if (this._isPlaying) {
throw new Error("Animation is already playing.");
}
let animationFinishedPromise = new Promise<void>((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
this._isPlaying = true;
if (this.delay !== 0) {
let that = this;
setTimeout(function (){ that.animate(view, 0, that.iterations); }, that.delay, that);
}
else {
this.animate(view, 0, this.iterations);
}
return animationFinishedPromise;
}
private animate(view: view.View, index: number, iterations: number) {
if (index === 0) {
let animation = this.animations[0];
let modifier = animation["valueSource"];
if ("backgroundColor" in animation) {
view.style._setValue(style.backgroundColorProperty, animation["backgroundColor"], modifier);
}
if ("scale" in animation) {
view.style._setValue(style.scaleXProperty, animation["scale"].x, modifier);
view.style._setValue(style.scaleYProperty, animation["scale"].y, modifier);
}
if ("translate" in animation) {
view.style._setValue(style.translateXProperty, animation["translate"].x, modifier);
view.style._setValue(style.translateYProperty, animation["translate"].y, modifier);
}
if ("rotate" in animation) {
view.style._setValue(style.rotateProperty, animation["rotate"], modifier);
}
if ("opacity" in animation) {
view.style._setValue(style.opacityProperty, animation["opacity"], modifier);
}
let that = this;
setTimeout(function () { that.animate(view, 1, iterations); }, 1, that);
}
else if (index < 0 || index >= this.animations.length) {
iterations -= 1;
if (iterations > 0) {
this.animate(view, 0, iterations);
}
else {
if (this._isForwards === false) {
let animation = this.animations[this.animations.length - 1];
let modifier = animation["valueSource"];
if ("backgroundColor" in animation) {
view.style._resetValue(style.backgroundColorProperty, modifier);
}
if ("scale" in animation) {
view.style._resetValue(style.scaleXProperty, modifier);
view.style._resetValue(style.scaleYProperty, modifier);
}
if ("translate" in animation) {
view.style._resetValue(style.translateXProperty, modifier);
view.style._resetValue(style.translateYProperty, modifier);
}
if ("rotate" in animation) {
view.style._resetValue(style.rotateProperty, modifier);
}
if ("opacity" in animation) {
view.style._resetValue(style.opacityProperty, modifier);
}
}
this._resolveAnimationFinishedPromise();
}
}
else {
view.animate(this.animations[index]).then(() => {
this.animate(view, index + 1, iterations);
});
}
}
public _resolveAnimationFinishedPromise() {
this._isPlaying = false;
this._resolve();
}
public _rejectAnimationFinishedPromise() {
this._isPlaying = false;
this._reject(new Error("Animation cancelled."));
}
}