/**
* Container class for all easings.
* @class
* @type {Ease}
*/
var Ease = {};
/**
* Linear easing.
* @description
* Formula
* `return x;`
*/
Ease.linear = function(v) { return v; }
/**
* Class that implements the animation/tweening features of SuitJS.
* @class
* @type Reel
*/
var Reel={};
(function(window,document,body) {
"use strict";
console.log("Reel> Init v1.0.0");
if(window.Servant==null) { console.error("Reel> Servant framework wasn't found!"); return; }
//List of supported units.
var m_units = ["px","%","em","rem","mm","cm","vw","vh","vmin","vmax","ex","ch","cm","pt","pc"];
/**
* Function that transforms the animation progress and eases the rate of change of the animated value.
* @callback Easing
* @param {Number} p_progress - Animation progress inside the range `[0.0,1.0]`.
* @returns {Number} - Returns the mapped progress inside the range `[0.0,1.0]`.
*/
/**
* Animation node.
* @typedef {Object} ReelAnimation
* @property {Object} target - Target object being animated.
* @property {String} property - Property name.
* @property {Object} value - Final value.
* @property {Easing} easing - Animation easing.
* @property {Number} delay - Delay in seconds.
* @property {Number} duration - Duration in seconds.
* @property {Number} elapsed - Elapsed time of execution in seconds.
* @property {Number} progress - Animation progress in the range `[0.0,1.0]`.
* @property {?(String|Function)} oncomplete - On complete callback. Can be either a function or `Suit`notification string.
* @property {?Boolean} runOnBackground - Flag that indicates this node will keep running when the tab isn't focused.
* @property {Function} update() - Execution method.
*/
/**
* List of active animations.
* @type {ReelAnimation[]}
*/
Reel.list = [];
/**
* Default duration in seconds when none is specified. Defaults to '0.3' seconds.
* @type {Number}
*/
Reel.defaultDuration = 0.3;
/**
* Default easing when none is specified. Defaults to 'Linear'.
* @type {Easing}
*/
Reel.defaultEasing = Linear;
/**
* Adds an Animation to the execution loop.
* @param {Object} p_target - Target object being animated.
* @param {String} p_property - Property to animate.
* @param {Object} p_value - Final value of the property.
* @param {?Number} p_duration - Duration in seconds. Defaults to `Reel.defaultDuration`.
* @param {?Number} p_delay - Delay before animation. Defaults to `0.0`.
* @param {?Easing} p_easing - Animation easing. Defaults to `Reel.defaultEasing`.
* @param {?Boolean} p_run_on_background - Flag that indicates the loop will keep running when the tab isn't focused.
* @returns {ReelAnimation} - Reference to the animation node created.
* @example
* var b = document.body;
* b.style.backgroundColor = "#fff";
* //Will animate with defaultEasing the 'body' background color during 3s but waiting 1s to start.
* Reel.add(b.style,"backgroundColor","#f00",3.0,1.0,Cubic.out);
*/
Reel.add =
function add(p_target,p_property,p_value,p_duration,p_delay,p_easing,p_run_on_background) {
var a = Servant;
var dl = p_delay == null ? 0.0 : p_delay;
var d = p_duration == null ? Reel.defaultDuration : p_duration;
var fn = p_easing == null ? Reel.defaultEasing : p_easing;
var hasStart = false;
var hasFinish = false;
var v0 = null;
var l = Reel.list;
var isString = typeof(p_target[p_property]) == "string";
var isNumber = typeof(p_target[p_property]) == "number";
var isObject = typeof(p_target[p_property]) == "object";
var vf = isString ? (p_value+"") : p_value;
var unit = "";
var isColor = false;
var c = {r:0,g:0,b:0};
if(isString) {
var v = vf.toLowerCase();
unit = "";
for(var i=0;i<m_units.length;i++) { if(v.indexOf(m_units[i]) >= 0) { unit = m_units[i]; break; } }
isColor = (v.indexOf("rgb") >= 0) ? true : false;
if(!isColor) {
if(v.indexOf("#")>=0) {
v = v.replace("#","");
var cr = parseInt(v.length >= 6 ? v.substr(0,2) : v.substr(0,1)+v.substr(0,1),16);
var cg = parseInt(v.length >= 6 ? v.substr(2,2) : v.substr(1,1)+v.substr(1,1),16);
var cb = parseInt(v.length >= 6 ? v.substr(4,2) : v.substr(2,1)+v.substr(2,1),16);
vf = "rgb("+cr+","+cg+","+cb+")";
isColor = true;
}
}
}
var res =
a.run(function(n) {
if(!hasStart) {
Reel.stop(p_target,p_property,[n]);
v0 = p_target[p_property];
if(isString) {
if(isColor) {
if(v0 == "") v0 = "rgb(255,255,255)";
v0 = v0.replace("rgb","").replace("(","").replace(")","").split(",");
vf = vf.replace("rgb","").replace("(","").replace(")","").split(",");
v0 = {r: parseInt(v0[0]), g: parseInt(v0[1]), b: parseInt(v0[2])};
vf = {r: parseInt(vf[0]), g: parseInt(vf[1]), b: parseInt(vf[2])};
}
else {
if(v0 == "") v0 = p_property == "opacity" ? "1.0" : "0.0";
v0 = v0.replace(unit,"");
v0 = unit == "" ? parseFloat(v0) : parseInt(v0);
vf = vf.replace(unit,"");
vf = unit == "" ? parseFloat(vf) : parseInt(vf);
}
}
hasStart = true;
}
var v1 = null;
var r = fn(n.progress);
if(isString) {
if(isColor) {
c.r = Math.floor(v0.r + (vf.r-v0.r) * r);
c.g = Math.floor(v0.g + (vf.g-v0.g) * r);
c.b = Math.floor(v0.b + (vf.b-v0.b) * r);
v1 = "rgb("+c.r+","+c.g+","+c.b+")";
}
else {
var res = v0 + (vf-v0) * r;
if(unit!="") res = Math.floor(res);
v1 = res+""+unit;
}
}
else {
v1 = v0 + (vf-v0) * r;
}
p_target[p_property] = v1;
if(n.progress >= 1.0) {
if(!hasFinish) {
if(n.oncomplete != null) {
if(typeof(n.oncomplete)=="string") {
if(window.Suit==null) {
console.error("Reel> Suit framework not found!");
}
window.Suit.controller.dispatch(n.oncomplete,n);
}
else {
n.oncomplete(n);
}
}
hasFinish=true;
var idx = l.indexOf(n);
if(idx>=0) l.splice(idx,1);
}
}
},d,dl,p_run_on_background);
res.target = p_target;
res.property = p_property;
res.value = p_value;
res.easing = fn;
res.delay = dl;
l.push(res);
return res;
};
/**
* Remove Animations that matches the specified criteria.
* @param {Object} p_target - Target object being animated.
* @param {?String} p_property - Property name to match. Defaults to `""` (stop all).
* @param {?ReelAnimation[]} p_ignore_list - List of animation nodes that must be ignored in the query.
* @example
* var b = document.body;
* //Starts animations.
* Reel.add(b.style,"backgroundColor","#f00",3.0);
* Reel.add(b.style,"width","50px",3.0);
*
* Reel.stop(b,"width"); //Stops only the 'width' animation
* Reel.stop(b); //Stops all animations for 'b'
*/
Reel.stop =
function stop(p_target,p_property,p_ignore_list) {
var l = Reel.list;
var il = p_ignore_list == null ? [] : p_ignore_list;
p_property = p_property == null ? "" : p_property;
for(var i=0;i<l.length;i++) {
var matchTarget = p_target == null ? true : (l[i].target == p_target);
if(matchTarget) {
var matchProperty = (l[i].property == p_property) || (p_property == "");
if(matchProperty) {
if(il.indexOf(l[i])<0) {
Servant.remove(l[i]);
l.splice(i--,1);
}
}
}
}
};
})(window,document,document.body);
/**
* Easing Equations by Robert Penner [http://robertpenner.com/easing/]
* More information [http://easings.net/]
*/
var PI2 = Math.PI*2.0;
var HalfPI = Math.PI*0.5;
var PI = Math.PI;
/**
* Quadratic easings.
* @class
* @type {Quad}
*/
Ease.quad = {};
(function() {
/**
* Quadratic In.
* Formula
* `return x^2;`
*/
Ease.quad.in = function(v) { return v*v; };
/**
* Quadratic Out.
* Formula
* `return -x*(x-2);`
*/
Ease.quad.out = function(v) { return -v*(v-2); };
/**
* Quadratic In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return 0.5*x*x;
* return -0.5 * ((--x)*(x-2.0) - 1.0);
* ```
*/
Ease.quad.inout = function(v) {
if ((v*=2.0) < 1.0) return 0.5*v*v;
return -0.5 * ((--v)*(v-2.0) - 1.0);
};
})();
/**
* Cubic easings.
* @class
* @type {Cubic}
*/
Ease.cubic = {};
(function() {
/**
* Cubic In.
* Formula
* `return x^3;`
*/
Ease.cubic.in = function(v) { return v*v*v; };
/**
* Cubic Out.
* Formula
* `return ((x=x-1)*x*x + 1.0);`
*/
Ease.cubic.out = function(v) { return ((v=v-1)*v*v + 1.0); };
/**
* Cubic In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return 0.5*(x^3);
* return 0.5*((x-=2.0)*x*x + 2.0);
* ```
*/
Ease.cubic.inout = function(v) {
if ((v*=2.0) < 1.0) return 0.5*v*v*v;
return 0.5*((v-=2.0)*v*v + 2.0);
};
})();
/**
* Quartic easings.
* @class
* @type {Quartic}
*/
Ease.quartic = {};
(function() {
/**
* Quartic In.
* Formula
* `return x^4;`
*/
Ease.quartic.in = function(v) { return v*v*v*v; };
/**
* Cubic Out.
* Formula
* `return -((x-1)*(x^3))-1;`
*/
Ease.quartic.out = function(v) { return -(((v=v-1.0)*v*v*v) - 1.0); };
/**
* Quartic In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return 0.5*(x^4);
* return -0.5 * (((x-=2.0)*(x^3)) - 2.0);
* ```
*/
Ease.quartic.inout = function(v) {
if ((v*=2.0) < 1.0) return 0.5*v*v*v*v;
return -0.5 * ((v-=2.0)*v*v*v - 2.0);
};
})();
/**
* Quintic easings.
* @class
* @type {Quintic}
*/
Ease.quintic = {};
(function() {
/**
* Quintic In.
* Formula
* `return x^5;`
*/
Ease.quintic.in = function(v) { return v*v*v*v*v; };
/**
* Quintic Out.
* Formula
* `return ((x-1)*(x^4)) + 1;`
*/
Ease.quintic.out = function(v) { return ((v=v-1)*v*v*v*v + 1); };
/**
* Quintic In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return 0.5*(x^5);
* return 0.5*((x-=2)*(x^4) + 2);
* ```
*/
Ease.quintic.inout = function(v) {
if ((v*=2.0) < 1.0) return 0.5*v*v*v*v*v;
return 0.5*((v-=2)*v*v*v*v + 2);
};
})();
/**
* Sine easings.
* @class
* @type {Sine}
*/
Ease.sine = {};
(function() {
/**
* Sine In.
* Formula
* `return -cos(x*PI*0.5)+1.0;`
*/
Ease.sine.in = function(v) { return -Math.cos(v * HalfPI) + 1.0; };
/**
* Sine Out.
* Formula
* `return sin(x*PI*0.5);`
*/
Ease.sine.out = function(v) { return Math.sin(v * HalfPI); };
/**
* Sine In-Out
* Formula
* `return -0.5*(cos(PI*x)-1.0);`
*/
Ease.sine.inout = function(v) { return -0.5 * (Math.cos(PI*v) - 1.0); };
})();
/**
* Exponential easings.
* @class
* @type {Expo}
*/
Ease.expo = {};
(function() {
/**
* Expo In.
* Formula
* `return x==0.0 ? 0.0 : 2.0^(10.0 * (x-1));`
*/
Ease.expo.in = function(v) { return (Math.abs(v)<=0.0001) ? 0 : Math.pow(2.0, 10.0 * (v - 1.0)); };
/**
* Expo Out.
* Formula
* `return x==1.0 ? 1.0 : (-2.0^(-10.0*x))+1.0;`
*/
Ease.expo.out = function(v) { return Math.abs(v-1.0)<=0.0001 ? 1.0 : -Math.pow(2.0, -10.0 * v) + 1; };
/**
* Expo In-Out
* Formula
* ```
* if(x==0.0) return 0.0;
* if(x==1.0) return 1.0;
* if ((x*=2.0) < 1.0) return 0.5 * Math.pow(2.0, 10.0 * (x - 1));
* return 0.5 * (-Math.pow(2.0, -10.0 * (--x)) + 2.0);
* ```
*/
Ease.expo.inout = function(v) {
if (Math.abs(v) <=0.0001) return 0.0;
if (Math.abs(v-1.0)<=0.0001) return 1.0;
if ((v*=2.0) < 1.0) return 0.5 * Math.pow(2.0, 10.0 * (v - 1));
return 0.5 * (-Math.pow(2.0, -10.0 * (--v)) + 2.0);
};
})();
/**
* Circular easings.
* @class
* @type {Circ}
*/
Ease.circ = {};
(function() {
/**
* Circ In.
* Formula
* `return -(sqrt(1.0 - (x^2)) - 1.0);`
*/
Ease.circ.in = function(v) { return -(Math.sqrt(1.0 - (v*v)) - 1.0); };
/**
* Circ Out.
* Formula
* `return sqrt(1.0 - (x=x-1)*x);`
*/
Ease.circ.out = function(v) { return Math.sqrt(1.0 - (v=v-1)*v); };
/**
* Circ In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return -0.5 * (sqrt(1.0 - (x^2)) - 1.0);
* return 0.5 * (sqrt(1.0 - (x-=2.0)*x) + 1.0);
* ```
*/
Ease.circ.inout = function(v) {
if ((v*=2.0) < 1.0) return -0.5 * (Math.sqrt(1.0 - (v*v)) - 1.0);
return 0.5 * (Math.sqrt(1.0 - (v-=2.0)*v) + 1.0);
};
})();
/**
* Elastic easings.
* @class
* @type {Elastic}
*/
Ease.elastic = {};
(function() {
/**
* Elastic In.
* Formula
* ```
* if(x==0.0) return 0.0;
* if(x==1.0) return 1.0;
* return -((2.0^(10.0*(x-=1)) * sin((x-0.075)*PI*2.0*3.3333));
* ```
*/
Ease.elastic.in = function(v) {
if (Math.abs(v) <=0.0001) return 0.0;
if (Math.abs(v-1.0)<=0.0001) return 1.0;
return -(Math.pow(2.0,10.0*(v-=1)) * Math.sin( (v-0.075)*PI2*3.3333));
};
/**
* Elastic Out.
* Formula
* ```
* if(x==0.0) return 0.0;
* if(x==1.0) return 1.0;
* return (2.0^(-10.0*x)) * sin((x-0.075)*PI*2.0*3.3333)+1.0);
* ```
*/
Ease.elastic.out = function(v) {
if (Math.abs(v) <=0.0001) return 0.0;
if (Math.abs(v-1.0)<=0.0001) return 1.0;
return (Math.pow(2.0,-10.0*v) * Math.sin((v-0.075)*PI2*3.3333)+1.0);
};
/**
* Elastic In-Out
* Formula
* ```
* if(x==0.0) return 0.0;
* if(x==1.0) return 1.0;
* if (x < 1.0) return -0.5*((2.0^(10.0*(x-=1.0)))*sin((x-0.1125)*PI*2.0*2.2222));
* return (pow(2.0,-10.0*(x-=1)) * sin((x-0.1125)*PI2*2.22222)*0.5) + 1.0;
* ```
*/
Ease.elastic.inout = function(v) {
if (Math.abs(v) <=0.0001) return 0.0;
if (Math.abs(v-1.0) <=0.0001) return 1.0;
if (v < 1.0) return -0.5*(Math.pow(2.0,10.0*(v-=1.0)) * Math.sin((v-0.1125)*PI2*2.2222));
return (Math.pow(2.0,-10.0*(v-=1)) * Math.sin((v-0.1125)*PI2*2.22222)*0.5) + 1.0;
};
})();
/**
* Back easings.
* @class
* @type {Elastic}
*/
Ease.back = {};
(function() {
/**
* Back In.
* Formula
* `return (x^2)*((2.70158*x) - 1.70158);`
*/
Ease.back.in = function(v) { return v*v*((2.70158*v) - 1.70158); };
/**
* Back Out.
* Formula
* `return ((x-1)*x*((2.70158*x) + 1.70158) + 1.0);`
*/
Ease.back.out = function(v) { return ((v=v-1.0)*v*((2.70158*v) + 1.70158) + 1.0); };
/**
* Back In-Out
* Formula
* ```
* if ((x*=2.0) < 1.0) return 0.5*((x^2)*((3.5949095*x) - 2.5949095));
* return 0.5*((x-=2.0)*x*((3.5949095)*x + 2.5949095) + 2.0);
* ```
*/
Ease.back.inout = function(v) {
if ((v*=2.0) < 1.0) return 0.5*(v*v*((3.5949095*v) - 2.5949095));
return 0.5*((v-=2.0)*v*((3.5949095)*v + 2.5949095) + 2.0);
};
})();
/**
* Bounce easings.
* @class
* @type {Bounce}
*/
Ease.bounce = {};
(function() {
/**
* Bounce In.
* Formula
* `return 1.0 - Bounce.out(1.0-x);`
*/
Ease.bounce.in = function(v) { return 1.0 - Bounce.out(1.0-v); };
/**
* Bounce Out.
* Formula
* ```
* if (x < 0.363636) return (7.5625*x*x); else
* if (x < 0.727272) return ((7.5625*(x-=0.545454)*x) + 0.75); else
* if (x < 0.909090) return ((7.5625*(x-=0.818181)*x) + 0.9375); else
* return ((7.5625*(x-=0.954545)*x) + 0.984375);
* ```
*/
Ease.bounce.out = function(v) {
if (v < 0.363636) return (7.5625*v*v); else
if (v < 0.727272) return ((7.5625*(v-=0.545454)*v) + 0.75); else
if (v < 0.909090) return ((7.5625*(v-=0.818181)*v) + 0.9375); else
return ((7.5625*(v-=0.954545)*v) + 0.984375);
};
/**
* Bounce In-Out
* Formula
* ```
* if (x < 0.5) return Bounce.in(x*2) * 0.5;
* return (Bounce.out((x*2.0)-1.0) * 0.5) + 0.5;
* ```
*/
Ease.bounce.inout = function(v) {
if (v < 0.5) return Bounce.in(v*2) * 0.5;
return (Bounce.out((v*2.0)-1.0) * 0.5) + 0.5;
};
})();