455 lines
7.3 KiB
JavaScript
455 lines
7.3 KiB
JavaScript
|
|
/*
|
||
|
|
|
||
|
|
Copyright (c) 2020, 2023, The Unified Company.
|
||
|
|
|
||
|
|
This code is part of Unify.
|
||
|
|
|
||
|
|
This program is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE,
|
||
|
|
as published by the Free Software Foundation.
|
||
|
|
See the GNU AFFERO GENERAL PUBLIC LICENSE, for more details.
|
||
|
|
|
||
|
|
https://unifyjs.org
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
import animation from "./animation.js";
|
||
|
|
|
||
|
|
|
||
|
|
export default class animationManager{
|
||
|
|
|
||
|
|
id = 0;
|
||
|
|
|
||
|
|
start = 0;
|
||
|
|
|
||
|
|
|
||
|
|
animations = new Array();
|
||
|
|
|
||
|
|
element = document.querySelector(".test");
|
||
|
|
|
||
|
|
promises = new Array();
|
||
|
|
|
||
|
|
eventListener;
|
||
|
|
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
|
||
|
|
this.id = document.animationID++;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createAnimation( name ) {
|
||
|
|
|
||
|
|
var newAnimation = new animation();
|
||
|
|
|
||
|
|
newAnimation.animationManager = this
|
||
|
|
|
||
|
|
newAnimation.id = document.keyframeID++;
|
||
|
|
|
||
|
|
newAnimation.name = name + newAnimation.id;
|
||
|
|
|
||
|
|
newAnimation.element = this.element;
|
||
|
|
|
||
|
|
newAnimation.created = false;
|
||
|
|
|
||
|
|
|
||
|
|
this.animations[ newAnimation.name ] = newAnimation;
|
||
|
|
|
||
|
|
|
||
|
|
this.createListeners( newAnimation );
|
||
|
|
|
||
|
|
return newAnimation;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
getAnimationClassName() {
|
||
|
|
|
||
|
|
return "keyFrameAnimation" + this.id;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createListeners( animation ) {
|
||
|
|
|
||
|
|
if( !animation.direction ) {
|
||
|
|
|
||
|
|
animation.__direction = "normal"
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
animation.__direction = animation.direction;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
var that = this;
|
||
|
|
|
||
|
|
animation.__defineSetter__( "direction", function( value ){
|
||
|
|
|
||
|
|
animation.__direction = value;
|
||
|
|
|
||
|
|
var animationManager = animation.animationManager;
|
||
|
|
|
||
|
|
var source = that.composeCss();
|
||
|
|
|
||
|
|
animation.writeStyleToDOM( source );
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
animation.__defineGetter__( "direction", function(){
|
||
|
|
|
||
|
|
return animation.__direction;
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
composeKeyFrameCss( source ) {
|
||
|
|
|
||
|
|
var animations = this.animations;
|
||
|
|
|
||
|
|
for ( var i in animations ) {
|
||
|
|
|
||
|
|
var currentAnimation = animations[i];
|
||
|
|
|
||
|
|
//if( !currentAnimation.active ) {
|
||
|
|
|
||
|
|
source += "@keyframes " + currentAnimation.name + "{ \n";
|
||
|
|
|
||
|
|
var keyFrames = currentAnimation.keyFrames;
|
||
|
|
|
||
|
|
for (var i = 0; i < keyFrames.length; i++) {
|
||
|
|
|
||
|
|
var currentKeyFrame = keyFrames[i];
|
||
|
|
|
||
|
|
|
||
|
|
source += "\t" + currentKeyFrame.percent + "% {";
|
||
|
|
|
||
|
|
source += currentKeyFrame.composeCss();
|
||
|
|
|
||
|
|
source += "}\n";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
source += "} \n";
|
||
|
|
|
||
|
|
currentAnimation.created = true;
|
||
|
|
|
||
|
|
//}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return source;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
composeAnimationCss( source ) {
|
||
|
|
|
||
|
|
var names = new Array();
|
||
|
|
|
||
|
|
var durations = new Array();
|
||
|
|
|
||
|
|
var interationCounts = new Array();
|
||
|
|
|
||
|
|
var fillModes = new Array();
|
||
|
|
|
||
|
|
var directions = new Array();
|
||
|
|
|
||
|
|
|
||
|
|
var animations = this.animations;
|
||
|
|
|
||
|
|
|
||
|
|
for ( var i in animations ) {
|
||
|
|
|
||
|
|
var currentAnimation = animations[i];
|
||
|
|
|
||
|
|
if( currentAnimation.active ) {
|
||
|
|
|
||
|
|
if( currentAnimation.duration ) {
|
||
|
|
|
||
|
|
names.push( currentAnimation.name );
|
||
|
|
|
||
|
|
durations.push( currentAnimation.duration );
|
||
|
|
|
||
|
|
directions.push( currentAnimation.direction );
|
||
|
|
|
||
|
|
|
||
|
|
if( !currentAnimation.iterationCount ) {
|
||
|
|
|
||
|
|
currentAnimation.iterationCount = 1;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
interationCounts.push( currentAnimation.iterationCount );
|
||
|
|
|
||
|
|
if( !currentAnimation.fillMode ) {
|
||
|
|
|
||
|
|
currentAnimation.fillMode = "none";
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
fillModes.push( currentAnimation.fillMode );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
source += ".keyFrameAnimation" + this.id + "{\n";
|
||
|
|
|
||
|
|
source += "\tanimation-name: " + names.join(",") + ";\n";
|
||
|
|
|
||
|
|
source += "\tanimation-duration: " + durations.join(",") + ";\n";
|
||
|
|
|
||
|
|
source += "\tanimation-iteration-count: " + interationCounts.join(",") + ";\n";
|
||
|
|
|
||
|
|
source += "\tanimation-fill-mode: " + fillModes.join(",") + ";\n";
|
||
|
|
|
||
|
|
source += "\tanimation-direction: " + directions.join(",") + ";\n";
|
||
|
|
|
||
|
|
source += "}";
|
||
|
|
|
||
|
|
|
||
|
|
return source;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
composeCss() {
|
||
|
|
|
||
|
|
var source = "";
|
||
|
|
|
||
|
|
source += this.composeKeyFrameCss( source );
|
||
|
|
|
||
|
|
source += this.composeAnimationCss( source );
|
||
|
|
|
||
|
|
return source;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
addPromise( promiseObject ) {
|
||
|
|
|
||
|
|
this.promises[ promiseObject.id ] = promiseObject;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
getPromiseByID( id ) {
|
||
|
|
|
||
|
|
return this.promises[ id ];
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createPromiseFunction( animationID ) {
|
||
|
|
|
||
|
|
var that = this;
|
||
|
|
|
||
|
|
function promiseFunction( resolveFunction ){
|
||
|
|
|
||
|
|
var promiseObject = {};
|
||
|
|
|
||
|
|
promiseObject.id = animationID;
|
||
|
|
|
||
|
|
promiseObject.resolve = resolveFunction;
|
||
|
|
|
||
|
|
that.addPromise( promiseObject );
|
||
|
|
}
|
||
|
|
|
||
|
|
return promiseFunction;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
attach( object ){
|
||
|
|
|
||
|
|
object.__proto__.animate = this.createCallback( object );
|
||
|
|
|
||
|
|
var animationManager = this;
|
||
|
|
|
||
|
|
object.createAnimation = function( name ) {
|
||
|
|
|
||
|
|
return object.animationManager.createAnimation( name );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
this.element = object.element;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createCallback( object ) {
|
||
|
|
|
||
|
|
object.animationManager.object = object;
|
||
|
|
|
||
|
|
return async function( from, to, callback ) {
|
||
|
|
|
||
|
|
return object.animationManager.animate( from, to, callback );
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
async animate( from, to, callback, firstTick = true, animationID, value = false, start = false ) {
|
||
|
|
|
||
|
|
var object = this.object;
|
||
|
|
|
||
|
|
if( firstTick ) {
|
||
|
|
|
||
|
|
animationID = document.animationID++;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
var sign = Math.sign( from - to );
|
||
|
|
|
||
|
|
var stop = false;
|
||
|
|
|
||
|
|
if( sign > 0) {
|
||
|
|
|
||
|
|
value = from - value;
|
||
|
|
|
||
|
|
if( value < to ) {
|
||
|
|
|
||
|
|
var stop = true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
value = from + value;
|
||
|
|
|
||
|
|
if( value > to ) {
|
||
|
|
|
||
|
|
var stop = true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( firstTick ) {
|
||
|
|
|
||
|
|
this.object[ "animationCallback" + animationID ] = callback;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( !stop ) {
|
||
|
|
|
||
|
|
this.object[ "animationCallback" + animationID ]( value );
|
||
|
|
|
||
|
|
window.requestAnimationFrame( function( timestamp ) {
|
||
|
|
|
||
|
|
if( !start ) {
|
||
|
|
|
||
|
|
start = timestamp;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
var progress = ( timestamp - start );
|
||
|
|
|
||
|
|
object.animationManager.animate( from, to, callback, false, animationID, progress, start );
|
||
|
|
|
||
|
|
});
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
var promise = this.getPromiseByID( animationID );
|
||
|
|
|
||
|
|
promise.resolve();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if( firstTick ) {
|
||
|
|
|
||
|
|
this.object[ "animationCallback" + animationID ]( value );
|
||
|
|
|
||
|
|
var promiseFunction = this.createPromiseFunction( animationID );
|
||
|
|
|
||
|
|
await new Promise( promiseFunction )
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
createEventListener() {
|
||
|
|
|
||
|
|
var that = this;
|
||
|
|
|
||
|
|
if( this.element.keyFrameEventListener ) {
|
||
|
|
|
||
|
|
canvas.removeEventListener('click', this.element.keyFrameEventListener);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
this.element.keyFrameEventListener = this.element.addEventListener("animationend", async function( event ) {
|
||
|
|
|
||
|
|
var animations = that.animations;
|
||
|
|
|
||
|
|
var animationName = event.animationName;
|
||
|
|
|
||
|
|
//console.log(animationName, that.promises);
|
||
|
|
|
||
|
|
//console.log(animations, animationName)
|
||
|
|
|
||
|
|
var currentAnimation = animations[ animationName ];
|
||
|
|
|
||
|
|
console.log("turn off animation", currentAnimation);
|
||
|
|
|
||
|
|
currentAnimation.active = false;
|
||
|
|
|
||
|
|
//console.log("promise with animationName", animationName, "and animationID", currentAnimation.animationID, "removed");
|
||
|
|
|
||
|
|
if( currentAnimation ) {
|
||
|
|
|
||
|
|
var promise = that.promises[currentAnimation.id];
|
||
|
|
|
||
|
|
if( promise ) {
|
||
|
|
|
||
|
|
promise.resolve();
|
||
|
|
|
||
|
|
} else {
|
||
|
|
|
||
|
|
return false;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
//console.log("ended animation", currentAnimation);
|
||
|
|
|
||
|
|
that.promises.splice( currentAnimation.id, 1, false )
|
||
|
|
|
||
|
|
for (var i = 0; i < that.promises.length; i++) {
|
||
|
|
|
||
|
|
if( that.promises[i] ) {
|
||
|
|
|
||
|
|
return false
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//console.log("all promises are resolved resetting animation");
|
||
|
|
|
||
|
|
//that.resetAnimation();
|
||
|
|
|
||
|
|
var animationClassName = that.getAnimationClassName();
|
||
|
|
|
||
|
|
that.element.classList.remove(animationClassName);
|
||
|
|
|
||
|
|
}, false);
|
||
|
|
|
||
|
|
return true;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
resetAnimation() {
|
||
|
|
|
||
|
|
//if( this.element.classList.contains("keyFrameAnimations") ) {
|
||
|
|
|
||
|
|
this.element.classList.remove("keyFrameAnimations")
|
||
|
|
|
||
|
|
//}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|