Skip to content

Instantly share code, notes, and snippets.

@kgn
Created November 29, 2010 07:22
Show Gist options
  • Star 24 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save kgn/719686 to your computer and use it in GitHub Desktop.
Save kgn/719686 to your computer and use it in GitHub Desktop.
jQuery plugin to display an animated image sequence.
//By David Keegan
//InScopeApps.com
//http://inscopeapps.com/demos/flipbook/
(function($){
$.fn.flipbook = function(options){
options = $.extend({
'start': 0, //start frame
'end': 100, //end frame, must be greater then start
'step': 1, //number of frames to step over while animating
'mobileStep': 3, //number of frames to step over when on a mobile device
'fps': 15, //frames per second, this will be adjusted correctly for step>1
'loop': false, //loop the animation
//the image path, uses %d to designate where the frame number goes.
//%#d can be used to specify padding
'images': ''
}, options);
var animatingAttr = 'flipbook_animating';
//if we are on a mobile webbrowser use the mobile step for better playback
var is_mobile = (navigator.userAgent.toLowerCase().indexOf('mobile')>=0);
function clamp(value, min){
if(value < min){
return min;
}
return value;
}
function padFrame(frame, padding){
var frameString = frame+'';
var delta = padding-frameString.length;
for(var i=0; i<delta; ++i){
frameString = '0'+frameString;
}
return frameString;
}
return this.each(function(){
var $image = $(this);
//check if the image is already animating
if($image.attr(animatingAttr) === 'true'){
return;
}
//find image parts
var images = $image.attr('images')||options.images;
var imagesMatch = images.match(/([^%]*)%(\d?)d(.*)/);
if(imagesMatch === null){
console.error('"'+images+'" does not conform to images convention, it should be like "frame.%d.jpg" or "frame.%4d.jpg"');
return;
}
var imagesFrontString = imagesMatch[1];
var framePadding = 0;
var imagesEndString = imagesMatch[2];
//if frame padding is specified
if(imagesMatch.length === 4){
framePadding = parseInt(imagesMatch[2], 10);
imagesEndString = imagesMatch[3];
}
//get the rest of the values from the img or the options
var start = parseInt($image.attr('start')||options.start, 10);
var end = parseInt($image.attr('end')||options.end, 10);
if(start > end){
console.error('"start" cannot be larger then "end"');
return;
}
var step = $image.attr('step')||options.step;
if(is_mobile){
step = $image.attr('mobileStep')||options.mobileStep;
}
step = clamp(parseInt(step, 10), 1);
var fps = clamp(parseInt($image.attr('fps')||options.fps, 10), 1);
var loop = $image.attr('loop')||options.loop;
if(loop === 'true'){
loop = true;
}else if(loop === 'false'){
loop = false;
}
//calculate the hold time taking into acount frame step
var holdTime = 1000/(fps/step);
function imageName(frame){
return imagesFrontString+padFrame(frame, framePadding)+imagesEndString;
}
var frameNumber = start;
$image.attr('src', imageName(frameNumber));
$image.attr(animatingAttr, 'true');
//increment frameNumber and change the image
function flipImage(){
//increment the frame
frameNumber += step;
//check if we've reached the end, if we have
//and loop is true set the frame back to the start frame
if(frameNumber > end && loop){
frameNumber = start;
}
//if we haven't reached the end yet update
//the image and start the cycle again
if(frameNumber <= end){
//console.log('set: '+imageName(frameNumber));
$image.attr('src', imageName(frameNumber));
setTimeout(flipImage, holdTime);
}else{
//always show the last image
$image.attr('src', imageName(end));
$image.attr(animatingAttr, 'false');
}
}
//preload images
var preloadCount = start;
//check if all the image have been preloaded,
//if they have start the animation
function shouldStartAnimation(){
//console.log('pre: '+imageName(i));
preloadCount += step;
if(preloadCount >= end){
setTimeout(flipImage, holdTime);
}
}
//asynchronously preload all images,
//then start the animation
for(var i=start; i<=end; i+=step){
$('<img/>').attr('src', imageName(i)).load(shouldStartAnimation);
}
});
};
})(jQuery);
@kgomara
Copy link

kgomara commented Oct 24, 2012

Thanks very much for sharing - great plug-in!

I'm fairly new to jquery - is there a way I can get a callback when the flipbook completes animating all the images?

@badoubadou
Copy link

Hi ! that look's great !
That's exactly what I need, to load a sequence of image, and preload them before starting the animation.
My question will look stupid sorry, but how do I use it ?
How do you start the fonction and how do you name the images ?
Is there a demo I didn't see somewhere ?
Thanks, and good job any way !

@badoubadou
Copy link

Ok, I opened my eyes, and find the demo.
Just wanted to say thanks you so much for this wonderful code.
I have made a call back if you're interested.

if(frameNumber > end && !loop && callback && !callbackdone){
callbackdone = true;
callback();
}

@TimJaramillo
Copy link

Hi there, first off- this is a great plugin, thanks for sharing it!

I'm trying to replay a sequence every 10 seconds via a setInterval.

I'm able to do this by creating a new flipbook object every time my setInterval fires. Is this the best way to initiate a timed-repeat, or is there a cleaner way?

$('#my-sequence').flipbook({
    'start': 0,
    'end': 10,
    'loop': false,
    'fps': 15,
    'step': 1,
    'images': 'images/my_image_%2d.png'
});

@rowspace
Copy link

rowspace commented Apr 1, 2013

Can't get this work--why cant a working html be provided?

@dazgreer
Copy link

Hi, I've implemented this and it is animating however it is skipping frames even though it's not set to. Here's the call:

$('.animation').flipbook({
'start': 1,
'end': 8,
'loop': false,
'fps': 1,
'images': 'img.%d.png'
});

When I comment out the console.log at line 109 and test the output, it get's called twice every second which effectively skips every other image. I've tried adding step: 1 but that doesn't make a difference.

Any ideas what's happening?

Thanks, Daz

@MiladJafari
Copy link

hhhh

@DariusNorv
Copy link

Hi there! Thanx for a great plugin. But I have one issue. Can I play animation in reverse?

@kaskajp
Copy link

kaskajp commented Dec 2, 2013

Very nice. But how can I stop a looping sequence?

@oraocean
Copy link

oraocean commented Apr 1, 2014

Does anyone has problems on I.E? It seems even official demo page can not work on I.E

@naveed-ahmad
Copy link

this need image for each frame for dam flip animation WAT?

FYI- http://www.turnjs.com/

@kyleoliveiro
Copy link

@naveed-ahmad This plugin is for animating image sequences, not for emulating a page flip animation...

@pdayya
Copy link

pdayya commented Oct 6, 2014

how to show multiple animation with same image sequence ?

@zur1eel
Copy link

zur1eel commented May 11, 2017

I'm searching the way to use this.

How do I use this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment