Skip to content

Instantly share code, notes, and snippets.

@jackmcmorrow
Created August 20, 2014 13:30
Show Gist options
  • Save jackmcmorrow/277069ce03ee96a0e420 to your computer and use it in GitHub Desktop.
Save jackmcmorrow/277069ce03ee96a0e420 to your computer and use it in GitHub Desktop.
Animation.js, a frame by frame animation lib
/*
// Animation CLASS
// @author cav_dan<daniel@shinka.com.br>
// @desc
// Create a frame-by-frame animation that may use jQuery
//
// @args
// selector = $('#someid') || document.querySelector('#someid'),
//
// optionsObj = {
// name: string || selector.id
// rootFolder: string = 'path/to/images'
// frames: objArray = ['first.png', 'second.png']
// }
//
// @example
// var char01 = new Animation($('#char01'), {rootFolder: 'img/char01/', frames: ['0.png', '1.png', '2.png']});
// char01.init() <-- creates the DOM elements
// char01.animate(0, this.length)
*/
var Animation = function(selector, optionsObj) {
this.selector = selector;
this.optionsObj = optionsObj;
this.frames = optionsObj.frames ? optionsObj.frames : [];
this.stopLoop = false;
this.onAnimationStart = function(){return true;};
this.onAnimationEnd = function(){return true;};
}
//Creates the DOM elements needed for the animation
Animation.prototype.init = function() {
var opts = this.optionsObj,
selector = this.selector,
framesDocFrag = document.createDocumentFragment(),
frames = [],
//Dentro de optionsObj definir uma array em frames
numOfFrames = opts.frames.length,
div, img, frameContainer;
if ( Array.isArray(selector) ) {
frameContainer = selector[0];
this.el = selector[0];
} else {
frameContainer = selector;
this.el = selector;
}
for (var i = 0; i <= opts.frames.length - 1; i++) {
div = document.createElement('div'),
img = document.createElement('img');
div.className = 'frame';
//div.style.zIndex = 100;
img.src = '';
div.appendChild(img);
img.src = opts.rootFolder + opts.frames[i];
//console.log(img.src);
opts.name = opts.name || 'animationFrame';
div.id = new String(opts.name + i);
framesDocFrag.appendChild(div);
/*if (i !== 0) {
div.style.display = 'none';
}*/
if (i !== 0) {
div.style.display = 'none';
}
frames.push(div);
frameContainer.appendChild(framesDocFrag);
};
frameContainer.style.width = opts.width || img.clientWidth + 'px';
frameContainer.style.height = opts.height || img.clientHeight + 'px';
frameContainer.style.overflow = 'hidden';
//frameContainer.style.zIndex = 200;
this.frames = frames;
}
/*
// @method Animate
// @args
// firstFrame = number,
// lastFrame = number,
// duration = number,
// isLoop = number || bool[false];
// callback = func
*/
Animation.prototype.animate = function(firstFrame, lastFrame, duration, isLoop, callback) {
var frames = this.frames,
duration = duration || 500;
//Verifica se passamos um callback antes do isLoop
if (typeof isLoop === 'function' || typeof isLoop === 'object') {
callback = isLoop;
isLoop = false;
}
this.callback = callback || false;
this.animating = true;
this.isLoop = isLoop || false;
if (this.callback && this.isLoop) {
isLoop = false;
console.warn("Callback can not be executed if you're looping: Loop has been turned off.");
}
this.onAnimationStart();
this.inverse = false;
if (lastFrame < firstFrame) {
//console.error("Last frame can't be before the first!");
//return false;
this.inverse = true;
} else if (lastFrame === firstFrame) {
lastFrame = frames.length - 1;
} else if (lastFrame > frames.length) {
lastFrame = frames.length;
}
//console.log('first: ' + firstFrame, '\nlast: ' + lastFrame, '\ndur: ' + duration, '\nloop?: ' + isLoop);
var betweenFrames;
this.anim = function() {
if (firstFrame !== 0 && lastFrame !== 0) {
frames[0].style.display = 'none';
}
/*if (this.lastUsedFrame) {
frames[this.lastUsedFrame].style.display = 'none';
}*/
//console.log(this.inverse);
//Se for ao contrário
if (this.inverse) {
betweenFrames = Math.floor( duration / (firstFrame - lastFrame) );
for (var i = firstFrame, animFrames = [], j = 0, _i = 0; i >= lastFrame; i--) {
//console.log( betweenFrames * _i );
// j foi declarado para que apenas seja alterado durante a execução
// da função anônima dentro do window.setTimeout.
animFrames.push(frames[i]);
setTimeout(function(){
frame = animFrames[j];
if (j !== 0) {
animFrames[j - 1].style.display = 'none';
}
frame.style.display = 'block';
//console.info(j, frame);
j++;
}, betweenFrames * _i);
_i++;
}
}
//Sentido normal
else {
betweenFrames = Math.floor( duration / (lastFrame - firstFrame) );
for (var i = firstFrame, animFrames = [], j = 0, _i = 0; i <= lastFrame; i++) {
//frames[i].style.display = 'none';
// j foi declarado para que apenas seja alterado durante a execução
// da função anônima dentro do window.setTimeout.
animFrames.push(frames[i]);
setTimeout(function(){
//console.log('animando');
frame = animFrames[j];
if (j !== 0) {
animFrames[j - 1].style.display = 'none';
}
frame.style.display = 'block';
//console.info(j, 'frame');
j++;
}, betweenFrames * _i);
_i++;
};
}
this.lastUsedFrame = lastFrame;
if (this.callback) {
this.callback();
};
}
if (this.isLoop) {
var that = this,
animationLoop = window.setInterval(function(){
if (that.stopLoop) {
/*that.lastFrame.style.display = 'none';
that.firstFrame.style.display = 'none';*/
that.stopLoop = false;
clearInterval(animationLoop);
}
that.anim();
//console.log('looping');
}, duration + isLoop);
} else {
this.anim();
}
for (var i = frames.length - 1; i >= 0; i--) {
if (i !== this.lastUsedFrame) {
frames[i].style.display = 'none';
}
};
this.onAnimationEnd();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment