Skip to content

Instantly share code, notes, and snippets.

@maolion
Last active August 29, 2015 14:10
Show Gist options
  • Save maolion/73f1f1a5d4142ac40b44 to your computer and use it in GitHub Desktop.
Save maolion/73f1f1a5d4142ac40b44 to your computer and use it in GitHub Desktop.
Animation
/// @require ../libs/jQuery/jquery.easing.1.3.js
var
Utils = require("./Utils.js"),
Env = require("./Env.js"),
Event = require("./Event.js"),
own = Object.prototype.hasOwnProperty,
slice = Array.prototype.slice
;
var
PLAY_STATE_NONE = 0,
PLAY_STATE_RUNNING = 1,
PLAY_STATE_PAUSED = 2,
PLAY_STATE_DONE = 3
;
var
transitions = {
linear : 'linear',
ease : 'ease',
easeIn : 'ease-in',
easeOut : 'ease-out',
easeInOut : 'ease-in-out',
easeInSine : 'cubic-bezier(0.47, 0, 0.745, 0.715)',
easeOutSine : 'cubic-bezier(0.39, 0.575, 0.565, 1)',
easeInOutSine : 'cubic-bezier(0.445, 0.05, 0.55, 0.95)',
easeInQuad : 'cubic-bezier(0.55, 0.085, 0.68, 0.53)',
easeOutQuad : 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
easeInOutQuad : 'cubic-bezier(0.455, 0.03, 0.515, 0.955)',
easeInCubic : 'cubic-bezier(0.55, 0.055, 0.675, 0.19)',
easeOutCubic : 'cubic-bezier(0.215, 0.61, 0.355, 1)',
easeInOutCubic : 'cubic-bezier(0.645, 0.045, 0.355, 1)',
easeInQuart : 'cubic-bezier(0.895, 0.03, 0.685, 0.22)',
easeOutQuart : 'cubic-bezier(0.165, 0.84, 0.44, 1)',
easeInOutQuart : 'cubic-bezier(0.77, 0, 0.175, 1)',
easeInQuint : 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
easeOutQuint : 'cubic-bezier(0.23, 1, 0.32, 1)',
easeInOutQuint : 'cubic-bezier(0.86, 0, 0.07, 1)',
easeInExpo : 'cubic-bezier(0.95, 0.05, 0.795, 0.035)',
easeOutExpo : 'cubic-bezier(0.19, 1, 0.22, 1)',
easeInOutExpo : 'cubic-bezier(1, 0, 0, 1)',
easeInCirc : 'cubic-bezier(0.6, 0.04, 0.98, 0.335)',
easeOutCirc : 'cubic-bezier(0.075, 0.82, 0.165, 1)',
easeInOutCirc : 'cubic-bezier(0.785, 0.135, 0.15, 0.86)',
easeInBack : 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',
easeOutBack : 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
easeInOutBack : 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
}
;
function Animate(opt){
var _this = this;
Event.call(this);
this.el = opt.element instanceof jQuery ? opt.element : jQuery(opt.element||document.body);
this.elStyle = this.el[0].style;
this.duration = opt.duration || 400;
this.delay = Math.max(~~opt.delay, 0);
this.timing = opt.timing || 'ease';
this.fillMode = opt.fillMode || 'forwards';
this.to = opt.to ? getCompatibilityStyle(opt.to) : {};
this.from = opt.from ? getCompatibilityStyle(opt.from) : {};
this.playState = PLAY_STATE_NONE;
this.startTime = 0;
this.currentTime = 0;
this.timer = null;
jQuery.each(['onStart', 'onPaused', 'onEnd'], function(index, event){
if (opt[event] instanceof Function) {
_this[event] = opt[event];
}
});
if (Env.CSS_SUPPORT.ANIMATE) {
this.timing = transitions[this.timing] || this.timing || 'ease';
this.property = function(){
var keys = [];
for(var k in _this.to) {
if (own.call(_this.to, k)) keys.push(toNormalizationtyleProperty(k));
}
return keys.join(",");
}();
this.el.on("webkitTransitionEnd transitionend", function(){
if (_this.playState !== PLAY_STATE_RUNNING) return;
_this.end();
});
} else {
this.animateDoneHandler = function(){
_this.end();
};
this.timing = own.call(jQuery.easing, this.timing) ? this.timing : 'swing';
}
};
var api = Animate.prototype = Utils.create(Event.prototype, Animate);
api.onStart =
api.onPaused =
api.onEnd = jQuery.noop;
[
function(){
api.play = function(){
var _this = this;
switch(this.playState) {
case PLAY_STATE_NONE:
case PLAY_STATE_DONE:
_this.timer = setTimeout(function(){
_this.playState = PLAY_STATE_RUNNING;
_this.currentTime = 0;
_this.startTime = new Date().getTime();
_this.el.stop()
.css(_this.from)
.animate(_this.to, _this.duration, _this.timing, _this.animateDoneHandler)
;
_this.onStart();
_this.fireEvent("start");
}, this.delay);
break;
case PLAY_STATE_PAUSED:
this.startTime = new Date().getTime();
this.playState = PLAY_STATE_RUNNING;
this.el.stop()
.animate(this.to, this.duration, this.timing, this.animateDoneHandler)
;
this.onStart();
this.fireEvent("start");
break;
}
};
api.pause = function(){
clearTimeout(this.timer);
if (this.playState !== PLAY_STATE_RUNNING) return;
this.currentTime += new Date().getTime() - this.startTime;
this.el.stop();
this.playState = PLAY_STATE_PAUSED;
this.onPaused();
this.fireEvent("paused");
};
api.end = function(){
if (this.playState === PLAY_STATE_DONE) return;
this.el.stop();
if (this.fillMode === 'forwards') {
if (this.playState === PLAY_STATE_PAUSED || this.currentTime + (new Date() - this.startTime) < this.duration) {
this.el.css(this.to);
}
} else {
this.el.css(this.from);
}
this.playState = PLAY_STATE_DONE;
this.currentTime = this.duration;
this.onEnd();
this.fireEvent("end");
};
},
function(){
api.play = function(){
var _this = this;
switch(this.playState) {
case PLAY_STATE_NONE:
case PLAY_STATE_DONE:
this.elStyle[Env.CSSPROP.transitionDuration] = '0ms';
this.elStyle[Env.CSSPROP.transitionTimingFunction] = this.timing;
this.elStyle[Env.CSSPROP.transitionProperty] = this.property;
_this.timer = setTimeout(function(){
setStyle(_this.elStyle, _this.from);
_this.timer = setTimeout(function(){
_this.playState = PLAY_STATE_RUNNING;
_this.currentTime = 0;
_this.startTime = new Date().getTime();
_this.elStyle[Env.CSSPROP.transitionDuration] = _this.duration + 'ms';
setStyle(_this.elStyle, _this.to);
_this.onStart();
_this.fireEvent("start");
}, 16);
}, this.delay);
break;
case PLAY_STATE_PAUSED:
_this.startTime = new Date().getTime();
this.playState = PLAY_STATE_RUNNING;
this.elStyle[Env.CSSPROP.transitionDuration] = (this.duration - this.currentTime) + 'ms';
setStyle(this.elStyle, this.to);
this.onStart();
this.fireEvent("start");
break;
}
};
api.pause = function(){
clearTimeout(this.timer);
if (this.playState !== PLAY_STATE_RUNNING) return;
this.currentTime += new Date().getTime() - this.startTime;
this.elStyle[Env.CSSPROP.transitionDuration] = '0ms';
var cStyle = window.getComputedStyle(this.el[0], null);
for(var k in this.to) {
if (!own.call(this.to, k)) continue;
this.elStyle[k] = cStyle[k];
}
this.playState = PLAY_STATE_PAUSED;
this.onPaused();
this.fireEvent("paused");
};
api.end = function(){
if (this.playState === PLAY_STATE_DONE) return;
this.elStyle[Env.CSSPROP.transition] = 'none';
if (this.fillMode === 'forwards') {
if (this.playState === PLAY_STATE_PAUSED || this.currentTime + (new Date() - this.startTime) < this.duration) {
setStyle(this.elStyle, this.to);
}
} else {
setStyle(this.elStyle, this.from);
}
this.playState = PLAY_STATE_DONE;
this.currentTime = this.duration;
this.onEnd();
this.fireEvent("end");
};
}
][+Env.CSS_SUPPORT.ANIMATE]();
function getCompatibilityStyle(style) {
var
r = {}
;
if (Env.CSS_SUPPORT.ANIMATE) {
var re = /^\*/;
style = style.CSS3 || style;
for(var k in style) {
if (!own.call(style, k)) continue;
r[toJsStyleProperty(k.replace(re, Env.CSS_VENDOR))] = style[k];
}
} else {
delete style.CSS3;
for(var k in style) {
if (!own.call(style, k)) continue;
r[toJsStyleProperty(k)] = style[k];
}
}
return r;
};
function toJsStyleProperty(name){
var
name = name.split('-'),
n = 0
;
for(var i = 0, l = name.length; i < l; i++) {
var p = name[i];
if (!p) continue;
name[n] = n === 0 ? p : p.charAt(0).toUpperCase() + p.slice(1);
n++;
}
name.length = n;
return name.join("");
}
function toNormalizationtyleProperty(name){
name = name.replace(/([A-Z])/g, function(match, $1){
return '-' + $1.toLowerCase()
});
if (/^(?:webkit|moz|ms|o)-/.test(name)) {
name = '-' + name;
}
return name;
}
function setStyle(style, css) {
for(var k in css) {
style[k] = css[k];
}
}
//x = new Animate({
// element : '#akd_logo',
// duration : 5000,
// fillMode : 'backwards',
// to : {
// left : 10,
// width : 100,
// CSS3 : {
// '*transform' : 'translateX(10px)',
// width : '100px'
// }
// },
// from : {
// left : 50,
// width : 200,
// CSS3 : {
// '*transform' : 'translateX(50px)',
// width : '200px'
// }
// }
//});
//x.onStart = function(){
// console.log("start");
//};
//x.onDone = function(){
// console.log("done");
// x.play();
//};
//x.onPaused = function(){
// console.log("paused");
//};
//x.play();
function Animation(){
Event.call(this);
var
_this = this,
animates = slice.call(arguments),
n = 0
;
jQuery.each(animates, function(index, animate){
if (!animate || !(animate instanceof Object)) return;
animate = animates[index = n++] = animate instanceof Animation ? animate : new Animate(animate);
animate.on("end", function(){
if (index + 1 >= _this._count) {
_this.end();
return;
}
animates[_this._currentIndex = index+1].play();
});
});
animates.length = n;
this._animates = animates;
this._currentIndex = 0;
this._count = animates.length;
this._playState = PLAY_STATE_NONE;
};
var api = Animation.prototype = Utils.create(Event.prototype, Animation);
api.onStart =
api.onPaused =
api.onEnd = jQuery.noop;
api.play = function() {
if (!this._count) return;
switch(this._playState) {
case PLAY_STATE_NONE:
case PLAY_STATE_DONE:
this._currentIndex = 0;
this._animates[0].play();
this._playState = PLAY_STATE_RUNNING;
this.onStart();
this.fireEvent("start");
break;
case PLAY_STATE_PAUSED:
this._animates[this._currentIndex].play();
this.onStart();
this.fireEvent("start");
break;
}
};
api.pause = function(){
if (!this._count) return;
if (this._playState === PLAY_STATE_PAUSED) return;
this._animates[this._currentIndex].pause();
this.onPaused();
this.fireEvent("paused");
};
api.end = function(){
if (!this._count) return;
if (this._playState === PLAY_STATE_DONE) return;
for(var i = this._animates.length; --i>=0;) this._animates[i].end();
this._currentIndex = this._count - 1;
this._playState = PLAY_STATE_DONE;
this.onEnd();
this.fireEvent("end");
};
api.isRunning = function() {
return this._playState === PLAY_STATE_RUNNING;
};
api.isPaused = function(){
return this._playState === PLAY_STATE_PAUSED;
};
api.isDone = function(){
return this._playState === PLAY_STATE_DONE;
};
module.exports = Animation;
//example
jQuery('#akd_logo').css('webkitAnimation', 'none');
x = new Animation(
{
element : '#akd_logo',
duration : 1200,
from : {
top : '50%',
opacity : 1,
CSS3 : {
'*transform' : 'translateY(0)',
opacity : 1
}
},
to : {
top : '20%',
opacity : 0,
CSS3 : {
'*transform' : 'translateY(-200px)',
opacity : 0
}
},
onStart : function() {
console.log("a");
}
},
{
element : '#akd_logo',
duration : 2000,
timing : 'easeOutBack',
from : {
top : '80%',
opacity : 0,
CSS3 : {
'*transform' : 'translateY(200px)',
opacity : 0
}
},
to : {
top : '50%',
opacity : 1,
CSS3 : {
'*transform' : 'translateY(0)',
opacity : 1
}
},
onStart : function(){
console.log("b");
}
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment