Created
January 20, 2016 14:28
-
-
Save macodev/5069124d5e0cdaa7ab74 to your computer and use it in GitHub Desktop.
jQuery plugin to display an animated image sequence. Added options for callback methods that are triggered when animation starts/ends.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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': '', | |
'startCallback':'', // A function to call once the animation starts | |
'startCallbackTimeout':0, // Time to wait until start function is called | |
'endCallback':'', // A function to call once the animation is complete | |
'endCallbackTimeout':1000 // Time to wait until end function is called | |
}, 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; | |
var i=0; | |
for(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 account 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'); | |
if(typeof(eval(options.endCallback)) === "function") { | |
setTimeout(options.endCallback +"()",options.endCallbackTimeout); | |
} | |
} | |
} | |
//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){ | |
if(typeof(eval(options.startCallback)) === "function") { | |
setTimeout(options.startCallback +"()",options.startCallbackTimeout); | |
} | |
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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment