@nativescript/core
Version:
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
238 lines • 9.25 kB
JavaScript
import { CoreTypes } from '../../core-types';
import { Trace } from '../../trace';
// Types.
import { unsetValue } from '../core/properties';
import { Animation } from '.';
import { backgroundColorProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, rotateProperty, opacityProperty, rotateXProperty, rotateYProperty, widthProperty, heightProperty } from '../styling/style-properties';
export class UnparsedKeyframe {
}
export class KeyframeDeclaration {
}
export class KeyframeInfo {
constructor() {
this.curve = CoreTypes.AnimationCurve.ease;
}
}
export class KeyframeAnimationInfo {
constructor() {
this.name = '';
this.duration = 0.3;
this.delay = 0;
this.iterations = 1;
this.curve = 'ease';
this.isForwards = false;
this.isReverse = false;
}
}
export class KeyframeAnimation {
constructor() {
this.delay = 0;
this.iterations = 1;
}
static keyframeAnimationFromInfo(info) {
if (!info?.keyframes?.length) {
Trace.write(`No keyframes found for animation '${info.name}'.`, Trace.categories.Animation, Trace.messageType.warn);
return null;
}
const length = info.keyframes.length;
const animations = new Array();
let startDuration = 0;
if (info.isReverse) {
for (let index = length - 1; index >= 0; index--) {
const keyframe = info.keyframes[index];
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration);
}
}
else {
for (let index = 0; index < length; index++) {
const keyframe = info.keyframes[index];
startDuration = KeyframeAnimation.parseKeyframe(info, keyframe, animations, startDuration);
}
for (let index = length - 1; index > 0; index--) {
const a1 = animations[index];
const a2 = animations[index - 1];
if (a2['curve'] !== undefined) {
a1['curve'] = a2['curve'];
a2['curve'] = undefined;
}
}
}
animations.map((a) => (a['curve'] ? a : Object.assign(a, { curve: info.curve })));
const animation = new KeyframeAnimation();
animation.delay = info.delay;
animation.iterations = info.iterations;
animation.animations = animations;
animation._isForwards = info.isForwards;
return animation;
}
static parseKeyframe(info, keyframe, animations, startDuration) {
const animation = {};
for (const 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 = 'keyframe';
animations.push(animation);
return startDuration;
}
get isPlaying() {
return this._isPlaying;
}
cancel() {
if (!this.isPlaying) {
Trace.write('Keyframe animation is already playing.', Trace.categories.Animation, Trace.messageType.warn);
return;
}
this._isPlaying = false;
for (let i = this._nativeAnimations.length - 1; i >= 0; i--) {
const animation = this._nativeAnimations[i];
if (animation.isPlaying) {
animation.cancel();
}
}
if (this._nativeAnimations.length > 0) {
const animation = this._nativeAnimations[0];
this._resetAnimationValues(this._target, animation);
}
this._resetAnimations();
}
play(view) {
if (this._isPlaying) {
Trace.write('Keyframe animation is already playing.', Trace.categories.Animation, Trace.messageType.warn);
return new Promise((resolve) => {
resolve();
});
}
const animationFinishedPromise = new Promise((resolve) => {
this._resolve = resolve;
});
this._isPlaying = true;
this._nativeAnimations = new Array();
this._target = view;
if (this.delay !== 0) {
setTimeout(() => this.animate(view, 0, this.iterations), this.delay);
}
else {
this.animate(view, 0, this.iterations);
}
return animationFinishedPromise;
}
animate(view, index, iterations) {
if (!this._isPlaying) {
return;
}
if (index === 0) {
const animation = this.animations[0];
if ('backgroundColor' in animation) {
view.style[backgroundColorProperty.keyframe] = animation.backgroundColor;
}
if ('scale' in animation) {
view.style[scaleXProperty.keyframe] = animation.scale.x;
view.style[scaleYProperty.keyframe] = animation.scale.y;
}
if ('translate' in animation) {
view.style[translateXProperty.keyframe] = animation.translate.x;
view.style[translateYProperty.keyframe] = animation.translate.y;
}
if ('rotate' in animation) {
view.style[rotateXProperty.keyframe] = animation.rotate.x;
view.style[rotateYProperty.keyframe] = animation.rotate.y;
view.style[rotateProperty.keyframe] = animation.rotate.z;
}
if ('opacity' in animation) {
view.style[opacityProperty.keyframe] = animation.opacity;
}
if ('height' in animation) {
view.style[heightProperty.keyframe] = animation.height;
}
if ('width' in animation) {
view.style[widthProperty.keyframe] = animation.width;
}
setTimeout(() => this.animate(view, 1, iterations), 1);
}
else if (index < 0 || index >= this.animations.length) {
iterations -= 1;
if (iterations > 0) {
this.animate(view, 0, iterations);
}
else {
if (this._isForwards === false) {
const animation = this.animations[this.animations.length - 1];
this._resetAnimationValues(view, animation);
}
this._resolveAnimationFinishedPromise();
}
}
else {
let animation;
const cachedAnimation = this._nativeAnimations[index - 1];
if (cachedAnimation) {
animation = cachedAnimation;
}
else {
const animationDef = { ...this.animations[index], target: view };
animation = new Animation([animationDef]);
this._nativeAnimations.push(animation);
}
const isLastIteration = iterations - 1 <= 0;
// Catch the animation cancel to prevent unhandled promise rejection warnings
animation
.play(isLastIteration)
.then(() => {
this.animate(view, index + 1, iterations);
}, (error) => {
Trace.write(typeof error === 'string' ? error : error.message, Trace.categories.Animation, Trace.messageType.warn);
})
.catch((error) => {
Trace.write(typeof error === 'string' ? error : error.message, Trace.categories.Animation, Trace.messageType.warn);
}); // tslint:disable-line
}
}
_resolveAnimationFinishedPromise() {
this._nativeAnimations = new Array();
this._isPlaying = false;
this._target = null;
this._resolve();
}
_resetAnimations() {
this._nativeAnimations = new Array();
this._isPlaying = false;
this._target = null;
}
_resetAnimationValues(view, animation) {
if ('backgroundColor' in animation) {
view.style[backgroundColorProperty.keyframe] = unsetValue;
}
if ('scale' in animation) {
view.style[scaleXProperty.keyframe] = unsetValue;
view.style[scaleYProperty.keyframe] = unsetValue;
}
if ('translate' in animation) {
view.style[translateXProperty.keyframe] = unsetValue;
view.style[translateYProperty.keyframe] = unsetValue;
}
if ('rotate' in animation) {
view.style[rotateProperty.keyframe] = unsetValue;
}
if ('opacity' in animation) {
view.style[opacityProperty.keyframe] = unsetValue;
}
if ('height' in animation) {
view.style[heightProperty.keyframe] = unsetValue;
}
if ('width' in animation) {
view.style[widthProperty.keyframe] = unsetValue;
}
}
}
//# sourceMappingURL=keyframe-animation.js.map