kute.js/kute.js
thednp 0b8d77c19b Changes:
* Recursive functions found in `examples.js` and `css.js`. Now `Maximum call stack size exceeded` error is completely eliminated
* Further optimization for the Tween object constructor
2016-10-12 06:44:42 +03:00

751 lines
35 KiB
JavaScript

/* KUTE.js - The Light Tweening Engine
* by dnp_theme
* Licensed under MIT-License
*/
(function (root,factory) {
if (typeof define === 'function' && define.amd) {
define([], factory); // AMD. Register as an anonymous module.
} else if (typeof exports == 'object') {
module.exports = factory(); // Node, not strict CommonJS
} else {
root.KUTE = factory();
}
}(this, function () {
"use strict";
// set a custom scope for KUTE.js
var g = typeof global !== 'undefined' ? global : window, K = {}, _tws = g._tweens = [], tick = null, time = g.performance,
getPrefix = function() { //returns browser prefix
var div = document.createElement('div'), i = 0, pf = ['Moz', 'moz', 'Webkit', 'webkit', 'O', 'o', 'Ms', 'ms'],
s = ['MozTransform', 'mozTransform', 'WebkitTransform', 'webkitTransform', 'OTransform', 'oTransform', 'MsTransform', 'msTransform'];
for (var i = 0, pl = pf.length; i < pl; i++) { if (s[i] in div.style) { return pf[i]; } }
div = null;
},
property = function(p){ // returns prefixed property | property
var r = (!(p in document.body.style)) ? true : false, f = getPrefix(); // is prefix required for property | prefix
return r ? f + (p.charAt(0).toUpperCase() + p.slice(1)) : p;
},
selector = function(el,multi){ // a selector utility
var nl;
if (multi){
nl = typeof el === 'object' ? el : document.querySelectorAll(el);
} else {
nl = typeof el === 'object' ? el
: /^#/.test(el) ? document.getElementById(el.replace('#','')) : document.querySelector(el);
}
if (nl === null && el !== 'window') throw new TypeError('Element not found or incorrect selector: '+el);
return nl;
},
trueDimension = function (d,p) { //true dimension returns { v = value, u = unit }
var x = parseInt(d) || 0, mu = ['px','%','deg','rad','em','rem','vh','vw'], y;
for (var i=0, l = mu.length; i<l; i++) { if ( typeof d === 'string' && d.indexOf(mu[i]) !== -1 ) { y = mu[i]; break; } }
y = y !== undefined ? y : (p ? 'deg' : 'px');
return { v: x, u: y };
},
trueColor = function (v) { // replace transparent and transform any color to rgba()/rgb()
if (/rgb|rgba/.test(v)) { //rgb will be fastest initialized
var vrgb = v.replace(/[^\d,]/g, '').split(','), y = vrgb[3] ? vrgb[3] : null;
if (!y) {
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]) };
} else {
return { r: parseInt(vrgb[0]), g: parseInt(vrgb[1]), b: parseInt(vrgb[2]), a: y*1 };
}
} else if (/^#/.test(v)) {
var fromHex = hexToRGB(v); return { r: fromHex.r, g: fromHex.g, b: fromHex.b };
} else if (/transparent|none|initial|inherit/.test(v)) {
return { r: 0, g: 0, b: 0, a: 0 };
} else if (!/^#|^rgb/.test(v) ) { // maybe we can check for web safe colors
var h = document.getElementsByTagName('head')[0]; h.style.color = v; var webColor = g.getComputedStyle(h,null).color;
h.style.color = ''; return v !== webColor ? { r: parseInt(webColor[0]), g: parseInt(webColor[1]), b: parseInt(webColor[2]) } : {r:0,g:0,b:0};
}
},
preventScroll = function (e) { // prevent mousewheel or touch events while tweening scroll
var data = document.body.getAttribute('data-tweening');
if (data && data === 'scroll') { e.preventDefault(); }
},
rgbToHex = function (r, g, b) { // transform rgb to hex or vice-versa | webkit browsers ignore HEX, always use RGB/RGBA
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
},
hexToRGB = function (hex) {
var shr = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
hex = hex.replace(shr, function (m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
},
getInlineStyle = function(el,p) { // getInlineStyle = get transform style for element from cssText for .to() method, the sp is for transform property
if (!el) return; // if the scroll applies to `window` it returns as it has no styling
var css = css || el.style.cssText.replace(/\s/g,'').split(';'),//the cssText
trsf = {}; //the transform object
// if we have any inline style in the cssText attribute, usually it has higher priority
for ( var i=0, csl = css.length; i<csl; i++ ){
if ( /transform/.test(css[i])) {
var tps = css[i].split(':')[1].split(')'); //all transform properties
for ( var k=0, tpl = tps.length-1; k< tpl; k++){
var tpv = tps[k].split('('), tp = tpv[0], tv = tpv[1]; //each transform property
if ( _tf.indexOf(tp) !== -1 ){
trsf[tp] = /translate3d/.test(tp) ? tv.split(',') : tv;
}
}
}
}
return trsf;
},
getCurrentStyle = function (el,p) { // gCS = get style property for element from computedStyle for .to() method
var es = el.style, cs = g.getComputedStyle(el,null) || el.currentStyle, pp = property(p), //the computed style | prefixed property
s = es[p] && !/auto|initial|none|unset/.test(es[p]) ? es[p] : cs[pp]; // s the property style value
if ( p !== 'transform' && (pp in cs || pp in es) ) {
if ( s ){
if (pp==='filter') { // handle IE8 opacity
var si1 = parseInt(s.split('=')[1].replace(')','')), si = parseFloat(si1/100);
return si;
} else {
return s;
}
} else {
return _d[p];
}
}
},
//more internals
getAll = function () { return _tws; },
removeAll = function () { _tws = []; },
add = function (tw) { _tws.push(tw); },
remove = function (tw) { var i = _tws.indexOf(tw); if (i !== -1) { _tws.splice(i, 1); }},
stop = function () { if (tick) { _caf(tick); tick = null; } },
canTouch = ('ontouchstart' in g || navigator.msMaxTouchPoints) || false, // support Touch?
touchOrWheel = canTouch ? 'touchstart' : 'mousewheel', mouseEnter = 'mouseenter', //events to prevent on scroll
_tr = property('transform'),
_raf = g.requestAnimationFrame || g.webkitRequestAnimationFrame || function (c) { return setTimeout(c, 16) },
_caf = g.cancelAnimationFrame || g.webkitCancelRequestAnimationFrame || function (c) { return clearTimeout(c) },
//true scroll container
body = document.body, html = document.getElementsByTagName('HTML')[0],
scrollContainer = /webkit/i.test(navigator.userAgent) || document.compatMode == 'BackCompat' ? body : html,
_isIE = navigator && (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) !== null) ? parseFloat( RegExp.$1 ) : false,
_isIE8 = _isIE === 8, // check IE8/IE
//supported properties
_cls = ['color', 'backgroundColor'], // colors 'hex', 'rgb', 'rgba' -- #fff / rgb(0,0,0) / rgba(0,0,0,0)
_sc = ['scrollTop', 'scroll'], //scroll, it has no default value, it's calculated on tween start
_op = ['opacity'], // opacity
_bm = ['top', 'left', 'width', 'height'], // dimensions / box model
_3d = ['rotateX', 'rotateY','translateZ'], // transform properties that require perspective
_tf = ['translate3d', 'translateX', 'translateY', 'translateZ', 'rotate', 'translate', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY', 'scale'], // transform
_all = _cls.concat(_sc, _op, _bm, _tf), al = _all.length,
_d = _d || {}; //all properties default values
//populate default values object
for ( var i=0; i<al; i++ ){
var p = _all[i];
if (_cls.indexOf(p) !== -1){
_d[p] = 'rgba(0,0,0,0)'; // _d[p] = {r:0,g:0,b:0,a:1};
} else if ( _bm.indexOf(p) !== -1 ) {
_d[p] = 0;
} else if ( p === 'translate3d' ){
_d[p] = [0,0,0];
} else if ( p === 'translate' ){
_d[p] = [0,0];
} else if ( p === 'rotate' || /X|Y|Z/.test(p) ){
_d[p] = 0;
} else if ( p === 'scale' || p === 'opacity' ){
_d[p] = 1;
}
}
// KUTE.js INTERPOLATORS
var Interpolate = g.Interpolate = {},
number = Interpolate.number = function(a,b,v) { // number1, number2, progress
a = +a; b -= a; return a + b * v;
},
unit = Interpolate.unit = function(a,b,u,v) { // number1, number2, unit, progress
a = +a; b -= a; return (a + b * v)+u;
},
color = Interpolate.color = function(a,b,v,h){ // rgba1, rgba2, progress, convertToHex(true/false)
var _c = {}, c, n = number, ep = ')', cm =',', r = 'rgb(', ra = 'rgba(';
for (c in b) { _c[c] = c !== 'a' ? (parseInt( number(a[c],b[c],v) ) || 0) : (a[c] && b[c]) ? parseFloat( number(a[c],b[c],v) ) : null; }
return h ? rgbToHex( _c.r, _c.g, _c.b ) : !_c.a ? r + _c.r + cm + _c.g + cm + _c.b + ep : ra + _c.r + cm + _c.g + cm + _c.b + cm + _c.a + ep;
},
translate = Interpolate.translate = function (a,b,v){
var ts = {};
for (var ax in b){
var x1 = a[ax].value || 0, x2 = b[ax].value || 0, xu = b[ax].unit || 'px';
ts[ax] = x1===x2 ? x2+xu : (x1 + ( x2 - x1 ) * v) + xu;
}
return b.x ? 'translate(' + ts.x + ',' + ts.y + ')' :
'translate3d(' + ts.translateX + ',' + ts.translateY + ',' + ts.translateZ + ')';
},
rotate = Interpolate.rotate = function (a,b,v){
var rS = {};
for ( var rx in b ){
if ( a[rx] ) {
var a1 = a[rx].value, a2 = b[rx].value, au = b[rx].unit||'deg', av = a1 + (a2 - a1) * v;
rS[rx] = rx === 'z' ? 'rotate('+av+au+')' : rx + '(' + av + au + ')';
}
}
return b.z ? rS.z : (rS.rotateX||'') + (rS.rotateY||'') + (rS.rotateZ||'');
},
skew = Interpolate.skew = function (a,b,v){
var sS = {};
for ( var sx in b ){
if ( a[sx] ) {
var s1 = a[sx].value, s2 = b[sx].value, su = b[sx].unit||'deg';
sS[sx] = sx + '(' + (s1 + (s2 - s1) * v) + su + ')';
}
}
return (sS.skewX||'') + (sS.skewY||'');
},
scale = Interpolate.scale = function(a,b,v){
var sc1 = a.value, sc2 = b.value;
return 'scale(' + (sc1 + (sc2 - sc1) * v) + ')';
},
// KUTE.js DOM update functions
DOM = g.dom = {},
ticker = g._ticker = function(t) {
var i = 0, l;
while ( i < (l=_tws.length) ) {
if ( update(_tws[i],t) ) {
i++;
} else {
_tws.splice(i, 1);
}
}
tick = _raf(ticker);
},
update = g._update = function(w,t) {
t = t || time.now();
if (t < w._sT && w.playing && !w.paused) { return true; }
// element/node, method, (prefixed)property, startValue, endValue, progress
var elapsed = Math.min(( t - w._sT ) / w._dr, 1); // calculate progress
for (var p in w._vE){ DOM[p](w._el,p,w._vS[p],w._vE[p],w._e(elapsed),w._ops); } //render the CSS update
if (w._uC) { w._uC.call(); } // fire the updateCallback, try to minimize recursion
if (elapsed === 1) {
if (w._r > 0) {
if ( w._r < 9999 ) { w._r--; } else { w._r = 9998; } // we have to make it stop somewhere, infinity is too damn much
if (w._y) { w.reversed = !w.reversed; reverse.call(w); } // handle yoyo
w._sT = (w._y && !w.reversed) ? t + w._rD : t; //set the right time for delay
return true;
} else {
if (w._cC) { w._cC.call(); }
scrollOut.call(w); // unbind preventing scroll when scroll tween finished
// start animating chained tweens
for (var i = 0, ctl = w._cT.length; i < ctl; i++) {
w._cT[i].start();
}
//stop ticking when finished
close.call(w);
}
return false;
}
return true;
},
// applies the transform origin and perspective
perspective = function (l,o) {
if ( o.transformOrigin !== undefined ) { l.style[property('transformOrigin')] = o.transformOrigin; } // element transform origin
if ( o.perspectiveOrigin !== undefined ) { l.style[property('perspectiveOrigin')] = o.perspectiveOrigin; } // element perspective origin
if ( o.parentPerspective !== undefined ) { l.parentNode.style[property('perspective')] = o.parentPerspective + 'px'; } // parent perspective
if ( o.parentPerspectiveOrigin !== undefined ) { l.parentNode.style[property('perspectiveOrigin')] = o.parentPerspectiveOrigin; } // parent perspective origin
},
// process properties for _vE and _vS or one of them
preparePropertiesObject = function (e, s, l) {
var pl = arguments.length, _st = []; pl = pl > 2 ? 2 : pl;
for (var i=0; i<pl; i++) {
var t = arguments[i], x, sk = {}, rt = {}, tl = {}, tr = {}; _st[i] = {};
for (x in t) {
if (_tf.indexOf(x) !== -1) { // transform object gets built here
if ( /^translate(?:[XYZ]|3d)$/.test(x) ) { //process translate3d
var ta = ['X', 'Y', 'Z']; //coordinates // translate[x] = pp(x, t[x]);
for (var f = 0; f < 3; f++) {
var a = ta[f];
if ( /3d/.test(x) ) {
tl['translate' + a] = parseProperty.transform('translate' + a, t[x][f]);
} else {
tl['translate' + a] = ('translate' + a in t) ? parseProperty.transform('translate' + a, t['translate' + a]) : { value: 0, unit: 'px' };
}
}
tr['translate'] = tl;
} else if ( /^rotate(?:[XYZ])$|^skew(?:[XY])$/.test(x) ) { //process rotation/skew
var ap = /rotate/.test(x) ? 'rotate' : 'skew', ra = ['X', 'Y', 'Z'],
rtp = ap === 'rotate' ? rt : sk;
for (var r = 0; r < 3; r++) {
var v = ra[r];
if ( t[ap+v] !== undefined && x !== 'skewZ' ) {
rtp[ap+v] = parseProperty.transform(ap+v, t[ap+v]);
}
}
tr[ap] = rtp;
} else if ( /(rotate|translate|scale)$/.test(x) ) { //process 2d translation / rotation
tr[x] = parseProperty.transform(x, t[x]);
}
_st[i]['transform'] = tr;
} else if ( x !== 'transform') {
if ( _bm.indexOf(x) !== -1 ) {
_st[i][x] = parseProperty.box(x,t[x]);
} else if (_op.indexOf(x) !== -1 || _sc.indexOf(x) !== -1) {
_st[i][x] = parseProperty.unl(x,t[x]);
} else if (_cls.indexOf(x) !== -1) {
_st[i][x] = parseProperty.cls(x,t[x]);
} else if (x in parseProperty) { _st[i][x] = parseProperty[x](x,t[x],l); } // or any other property from css/ attr / svg / third party plugins
}
}
}
return _st;
},
// process properties object | registers the plugins prepareStart functions
// string parsing and property specific value processing
parseProperty = {
box : function(p,v){ // box model | text props | radius props
if (!(p in DOM)){
DOM[p] = function(l,p,a,b,v){
l.style[p] = unit(a.value,b.value,b.unit,v);
}
}
return { value: trueDimension(v).v, unit: trueDimension(v).u };
},
transform : function(p,v){ // transform prop / value
if (!('transform' in DOM)) {
DOM.transform = function(l,p,a,b,v,o){
var _tS = '', t = '', r = '', sk = '', s = '', pp = pp || o.perspective && parseInt(o.perspective) !== 0 ? 'perspective('+parseInt(o.perspective)+'px) ' : 0;
for (var tp in b){
if (tp === 'translate'){
t += translate(a[tp],b[tp],v);
} else if (tp === 'rotate'){
r += rotate(a[tp],b[tp],v);
} else if (tp === 'skew'){
sk += skew(a[tp],b[tp],v);
} else if (tp === 'scale'){
s += scale(a[tp],b[tp],v);
}
}
_tS = t + r + sk + s;
l.style[_tr] = pp ? pp + _tS : _tS;
}
}
// process each transform property
if (/translate/.test(p)) {
if (p === 'translate3d') {
var t3d = v.split(',');
return {
translateX : { value: trueDimension(t3d[0]).v, unit: trueDimension(t3d[0]).u },
translateY : { value: trueDimension(t3d[1]).v, unit: trueDimension(t3d[1]).u },
translateZ : { value: trueDimension(t3d[2]).v, unit: trueDimension(t3d[2]).u }
};
} else if (/^translate(?:[XYZ])$/.test(p)) {
return { value: trueDimension(v).v, unit: (trueDimension(v).u||'px') };
} else if (p === 'translate') {
var tv = typeof v === 'string' ? v.split(',') : v, t2d = {};
if (tv instanceof Array) {
t2d.x = { value: trueDimension(tv[0]).v, unit: trueDimension(tv[0]).u },
t2d.y = { value: trueDimension(tv[1]).v, unit: trueDimension(tv[1]).u }
} else {
t2d.x = { value: trueDimension(tv).v, unit: trueDimension(tv).u },
t2d.y = { value: 0, unit: 'px' }
}
return t2d;
}
} else if (/rotate|skew/.test(p)) {
if (/^rotate(?:[XYZ])$|skew(?:[XY])$/.test(p)) {
return { value: trueDimension(v,true).v, unit: (trueDimension(v,true).u||'deg') };
} else if (p === 'rotate') {
var r2d = {};
r2d.z = { value: trueDimension(v,true).v, unit: (trueDimension(v,true).u||'deg') };
return r2d;
}
} else if (p === 'scale') {
return { value: parseFloat(v) }; // this must be parseFloat(v)
}
},
unl : function(p,v){ // scroll | opacity | unitless
if (/scroll/.test(p) && !(p in DOM) ){
DOM[p] = function(l,p,a,b,v) {
var el = el || (l === undefined || l === null) ? scrollContainer : l;
el.scrollTop = number(a,b,v);
};
} else if (p === 'opacity') {
if (!(p in DOM)) {
if (_isIE8) {
DOM[p] = function(l,p,a,b,v) {
var st = "alpha(opacity=", ep = ')';
l.style.filter = st + (number(a,b,v) * 100) + ep;
};
} else {
DOM[p] = function(l,p,a,b,v) {
l.style.opacity = number(a,b,v);
};
}
}
}
return parseFloat(v);
},
cls : function(p,v){ // colors
if (!(p in DOM)) {
DOM[p] = function(l,p,a,b,v,o) {
l.style[p] = color(a,b,v,o.keepHex);
};
}
return trueColor(v);
}
},
reverse = function () {
if (this._y) {
for (var p in this._vE) {
var tmp = this._vSR[p];
this._vSR[p] = this._vE[p];
this._vE[p] = tmp;
this._vS[p] = this._vSR[p];
}
}
},
close = function () { // when animation is finished reset repeat, yoyo&reversed tweens
if (_tws.length-1 === _tws.indexOf(this)) { setTimeout(function(){stop()}, 48); } // when all animations are finished, stop ticking after ~3 frames
// if (_tws.length === 0) { setTimeout(function(){stop()}, 48); } // when all animations are finished, stop ticking after ~3 frames
if (this.repeat > 0) { this._r = this.repeat; }
if (this._y && this.reversed===true) { reverse.call(this); this.reversed = false; }
this.playing = false;
},
scrollOut = function(){ //prevent scroll when tweening scroll
if (document.body.getAttribute('data-tweening') && ( 'scroll' in this._vE || 'scrollTop' in this._vE )) {
document.removeEventListener(touchOrWheel, preventScroll, false);
document.removeEventListener(mouseEnter, preventScroll, false);
document.body.removeAttribute('data-tweening');
}
},
scrollIn = function(){
if (!document.body.getAttribute('data-tweening') && ( 'scroll' in this._vE || 'scrollTop' in this._vE )) {
document.addEventListener(touchOrWheel, preventScroll, false);
document.addEventListener(mouseEnter, preventScroll, false);
document.body.setAttribute('data-tweening', 'scroll');
}
},
processEasing = function (es) { //process easing
if ( typeof es === 'function') {
return es;
} else if ( typeof es === 'string' ) {
if ( /easing|linear/.test(es) ) {
return easing[es]; // regular Robert Penner Easing Functions
} else if ( /bezier/.test(es) ) {
var bz = es.replace(/bezier|\s|\(|\)/g,'').split(',');
return g.Bezier( bz[0]*1,bz[1]*1,bz[2]*1,bz[3]*1 ); //bezier easing
} else if ( /physics/.test(es) ) {
return g.Physics[es](); // predefined physics bezier based easing functions
} else {
return g.Ease[es](); // predefined bezier based easing functions
}
}
},
prepareStart = {},
// core easing functions
easing = g.Easing = {};
easing.linear = function (t) { return t; };
easing.easingSinusoidalIn = function(t) { return -Math.cos(t * Math.PI / 2) + 1; };
easing.easingSinusoidalOut = function(t) { return Math.sin(t * Math.PI / 2); };
easing.easingSinusoidalInOut = function(t) { return -0.5 * (Math.cos(Math.PI * t) - 1); };
easing.easingQuadraticIn = function (t) { return t*t; };
easing.easingQuadraticOut = function (t) { return t*(2-t); };
easing.easingQuadraticInOut = function (t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; };
easing.easingCubicIn = function (t) { return t*t*t; };
easing.easingCubicOut = function (t) { return (--t)*t*t+1; };
easing.easingCubicInOut = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; };
easing.easingQuarticIn = function (t) { return t*t*t*t; };
easing.easingQuarticOut = function (t) { return 1-(--t)*t*t*t; };
easing.easingQuarticInOut = function (t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; };
easing.easingQuinticIn = function (t) { return t*t*t*t*t; };
easing.easingQuinticOut = function (t) { return 1+(--t)*t*t*t*t; };
easing.easingQuinticInOut = function (t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; };
easing.easingCircularIn = function(t) { return -(Math.sqrt(1 - (t * t)) - 1); };
easing.easingCircularOut = function(t) { return Math.sqrt(1 - (t = t - 1) * t); };
easing.easingCircularInOut = function(t) { return ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); };
easing.easingExponentialIn = function(t) { return Math.pow(2, 10 * (t - 1)) - 0.001; };
easing.easingExponentialOut = function(t) { return 1 - Math.pow(2, -10 * t); };
easing.easingExponentialInOut = function(t) { return (t *= 2) < 1 ? 0.5 * Math.pow(2, 10 * (t - 1)) : 0.5 * (2 - Math.pow(2, -10 * (t - 1))); };
easing.easingBackIn = function(t) { var s = 1.70158; return t * t * ((s + 1) * t - s); };
easing.easingBackOut = function(t) { var s = 1.70158; return --t * t * ((s + 1) * t + s) + 1; };
easing.easingBackInOut = function(t) { var s = 1.70158 * 1.525; if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s)); return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2); };
easing.easingElasticIn = function(t) {
var s, _kea = 0.1, _kep = 0.4;
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2;
return - ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) );
};
easing.easingElasticOut = function(t) {
var s, _kea = 0.1, _kep = 0.4;
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2 ;
return ( _kea * Math.pow( 2, - 10 * t) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) + 1 );
};
easing.easingElasticInOut = function(t) {
var s, _kea = 0.1, _kep = 0.4;
if ( t === 0 ) return 0; if ( t === 1 ) return 1;
if ( !_kea || _kea < 1 ) { _kea = 1; s = _kep / 4; } else s = _kep * Math.asin( 1 / _kea ) / Math.PI * 2 ;
if ( ( t *= 2 ) < 1 ) return - 0.5 * ( _kea * Math.pow( 2, 10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) );
return _kea * Math.pow( 2, -10 * ( t -= 1 ) ) * Math.sin( ( t - s ) * Math.PI * 2 / _kep ) * 0.5 + 1;
};
easing.easingBounceIn = function(t) { return 1 - easing.easingBounceOut( 1 - t ); };
easing.easingBounceOut = function(t) {
if ( t < ( 1 / 2.75 ) ) { return 7.5625 * t * t; }
else if ( t < ( 2 / 2.75 ) ) { return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75; }
else if ( t < ( 2.5 / 2.75 ) ) { return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375; }
else {return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375; }
};
easing.easingBounceInOut = function(t) { if ( t < 0.5 ) return easing.easingBounceIn( t * 2 ) * 0.5; return easing.easingBounceOut( t * 2 - 1 ) * 0.5 + 0.5;};
// single Tween object construct
var start = function (t) { // move functions that use the ticker outside the prototype to be in the same scope with it
scrollIn.call(this);
perspective(this._el,this._ops); // apply the perspective and transform origin
if ( this._rpr ) { this.getStartValues(); } // on start we reprocess the valuesStart for TO() method
K.svg && K.svq(this); // SVG Plugin | on start we process the SVG paths and SVG transforms
for ( var e in this._vE ) {
this._vSR[e] = this._vS[e];
}
// now it's a good time to start
_tws.push(this);
this.playing = true;
this.paused = false;
this._sCF = false;
this._sT = t || time.now();
this._sT += this._dl;
if (!this._sCF) {
if (this._sC) { this._sC.call(); }
this._sCF = true;
}
!tick && ticker();
return this;
},
play = function () {
if (this.paused && this.playing) {
this.paused = false;
if (this._rC !== null) { this._rC.call(); }
this._sT += time.now() - this._pST;
_tws.push(this);
!tick && ticker(); // restart ticking if stopped
}
return this;
},
Tween = g._tween = function (_el, _vS, _vE, _o) {
this._el = _el; // element animation is applied to
this._vSR = {}; // internal valuesStartRepeat
this._vS = _vS; // valuesStart
this._vE = _vE; // valuesEnd
this._y = _o.yoyo || false; // _yoyo
this.playing = false; // _isPlaying
this.reversed = false; // _reversed
this.paused = false; //_paused
this._sT = null; // startTime
this._pST = null; //_pauseStartTime
this._rpr = _o.rpr || false; // internal option to process inline/computed style at start instead of init true/false
this._dr = _o.duration || 700; //duration
this._r = _o.repeat || 0; // _repeat
this._rD = _o.repeatDelay || 0; // _repeatDelay
this._dl = _o.delay || 0; //delay
this._e = _o && _o.easing && typeof processEasing(_o.easing) === 'function' ? processEasing(_o.easing) : easing.linear; // _easing function
this._cT = []; //_chainedTweens
this._sCF = false; //_on StartCallbackFIRED
this._sC = _o.start || null; // _on StartCallback
this._uC = _o.update || null; // _on UpdateCallback
this._cC = _o.complete || null; // _on CompleteCallback
this._pC = _o.pause || null; // _on PauseCallback
this._rC = _o.play || null; // _on ResumeCallback
this._stC = _o.stop || null; // _on StopCallback
this.repeat = this._r; // we cache the number of repeats to be able to put it back after all cycles finish
this._ops = {};
this.start = start; this.play = play; this.resume = play;
//also add plugins options or transform perspective TO DO : split this damn regex into an array and do an indexOf or a simple ||
for (var o in _o) { if (!(o in this) && !/delay|rpr|duration|repeat|start|stop|update|complete|pause|play|yoyo|easing/i.test(o) ) { this._ops[o] = _o[o]; } }
this.pause = function() {
if (!this.paused && this.playing) {
remove(this);
this.paused = true;
this._pST = time.now();
if (this._pC !== null) {
this._pC.call();
}
}
return this;
};
this.stop = function () {
if (!this.paused && this.playing) {
remove(this);
this.playing = false;
this.paused = false;
scrollOut.call(this);
if (this._stC !== null) {
this._stC.call();
}
this.stopChainedTweens();
close.call(this);
}
return this;
};
this.chain = function () { this._cT = arguments; return this; };
this.stopChainedTweens = function () {
for (var i = 0, ctl =this._cT.length; i < ctl; i++) {
this._cT[i].stop();
}
};
this.getStartValues = function () { // stack transform props for .to() chains
var startValues = {}, cs = getInlineStyle(this._el,'transform'),
deg = ['rotate','skew'], ax = ['X','Y','Z'];
for (var p in _vS){
if ( _tf.indexOf(p) !== -1 ) {
var r2d = (/(rotate|translate|scale)$/.test(p));
if ( /translate/.test(p) && p !== 'translate' ) {
startValues['translate3d'] = cs['translate3d'] || _d[p];
} else if ( r2d ) { // 2d transforms
startValues[p] = cs[p] || _d[p];
} else if ( !r2d && /rotate|skew/.test(p) ) { // all angles
for (var d=0; d<2; d++) {
for (var a = 0; a<3; a++) {
var s = deg[d]+ax[a];
if (_tf.indexOf(s) !== -1 && (s in _vS) ) { startValues[s] = cs[s] || _d[s]; }
}
}
}
} else {
if ( _sc.indexOf(p) === -1 ) {
if (p === 'opacity' && _isIE8 ) { // handle IE8 opacity
var co = getCurrentStyle(this._el,'filter');
startValues['opacity'] = typeof co === 'number' ? co : _d['opacity'];
} else {
if ( _all.indexOf(p) !== -1 ) {
startValues[p] = getCurrentStyle(this._el,p) || d[p];
} else { // plugins register here
startValues[p] = p in prepareStart ? prepareStart[p](this._el,p,_vS[p]) : 0;
}
}
} else {
startValues[p] = (this._el === null || this._el === undefined) ? (g.pageYOffset || scrollContainer.scrollTop) : this._el.scrollTop;
}
}
}
for ( var p in cs ){ // also add to _vS values from previous tweens
if ( _tf.indexOf(p) !== -1 && (!( p in _vS )) ) {
startValues[p] = cs[p] || _d[p];
}
}
this._vS = {};
this._vS = preparePropertiesObject(startValues,{},this._el)[0];
if ( 'transform' in this._vE ){ // stack transform
var transform = 'transform';
for ( var sp in this._vS['transform']) {
if (!(sp in this._vE[transform])) { this._vE[transform][sp] = {}; }
for ( var spp in this._vS[transform][sp] ) { // 3rd level
if ( this._vS[transform][sp][spp].value !== undefined ) {
if (!(spp in this._vE[transform][sp])) { this._vE[transform][sp][spp] = {}; }
for ( var sppp in this._vS[transform][sp][spp]) { // spp = translateX | rotateX | skewX | rotate2d
if ( !(sppp in this._vE[transform][sp][spp])) {
this._vE[transform][sp][spp][sppp] = this._vS[transform][sp][spp][sppp]; // sppp = unit | value
}
}
}
}
if ( 'value' in this._vS[transform][sp] && (!('value' in this._vE[transform][sp])) ) { // 2nd level
for ( var spp1 in this._vS[transform][sp] ) { // scale
if (!(spp1 in this._vE[transform][sp])) {
this._vE[transform][sp][spp1] = this._vS[transform][sp][spp1]; // spp = unit | value
}
}
}
}
}
}
},
// the multi elements Tween constructs
TweensTO = function (els, vE, o) { // .to
this.tweens = []; var _o = [];
for ( var i = 0, tl = els.length; i < tl; i++ ) {
_o[i] = o || {}; o.delay = o.delay || 0;
_o[i].delay = i>0 ? o.delay + (o.offset||0) : o.delay;
this.tweens.push( to(els[i], vE, _o[i]) );
}
},
TweensFT = function (els, vS, vE, o) { // .fromTo
this.tweens = []; var _o = [];
for ( var i = 0, l = els.length; i < l; i++ ) {
_o[i] = o || {}; o.delay = o.delay || 0;
_o[i].delay = i>0 ? o.delay + (o.offset||0) : o.delay;
this.tweens.push( fromTo(els[i], vS, vE, _o[i]) );
}
},
ws = TweensTO.prototype = TweensFT.prototype = {
start : function(t){
t = t || time.now();
for ( var i = 0, tl = this.tweens.length; i < tl; i++ ) {
this.tweens[i].start(t);
}
return this;
},
stop : function(){ for ( var i = 0, tl = this.tweens.length; i < tl; i++ ) { this.tweens[i].stop(); } return this; },
pause : function(){ for ( var i = 0, tl = this.tweens.length; i < tl; i++ ) { this.tweens[i].pause(); } return this; },
chain : function(){ this.tweens[this.tweens.length-1]._cT = arguments; return this; },
play : function(){ for ( var i = 0, tl = this.tweens.length; i < tl; i++ ) { this.tweens[i].play(); } return this; },
resume : function() {return this.play()}
},
// main methods
to = function (el, to, o) {
var _el = selector(el),
_vS = to, _vE = preparePropertiesObject(to, {}, _el)[0]; o = o || {}; o.rpr = true;
return new Tween(_el, _vS, _vE, o);
},
fromTo = function (el, f, to, o) {
var _el = selector(el), ft = preparePropertiesObject(f, to, _el), _vS = ft[0], _vE = ft[1]; o = o || {};
var tw = new Tween(_el, _vS, _vE, o); K.svg && K.svq(tw); // on init we process the SVG paths
return tw;
},
// multiple elements tweening
allTo = function (els, to, o) {
var _els = selector(els,true);
return new TweensTO(_els, to, o);
},
allFromTo = function (els, f, to, o) {
var _els = selector(els,true);
return new TweensFT(_els, f, to, o);
};
return K = { // export core methods to public for plugins
property: property, getPrefix: getPrefix, selector: selector, pe : processEasing, // utils
to: to, fromTo: fromTo, allTo: allTo, allFromTo: allFromTo, // main methods
pp: parseProperty, prS: prepareStart, Tween : Tween, // property parsing & preparation | Tween
truD: trueDimension, truC: trueColor, rth: rgbToHex, htr: hexToRGB, gCS: getCurrentStyle, // property parsing
};
}));