PDA

View Full Version : Javascript Flipbook



fileserverdirect
10-31-2010, 01:15 AM
Hello all,
I have an interesting request from a client, A flipbook made out of javascript. The client sent me about 100 images, all frames from a flipbook, they would like to have them "animate" at about like 3 or 4 frames a second. My idea was to take a slide show script and time it down to like 300 milliseconds. I don't know a lot of javascript and don't worry, I've googled this for awhile and I can't find a solution. Is it better just to make a movie in Windows Movie Maker, or is this possible in JavaScript? My only concern is that the user would literally have to wait for all of the images to load. Can anyone point me in the right direction?

Nile
10-31-2010, 01:28 AM
Well, first I would make an array in java script of all those images with PHP using glob. The javascript shouldnt be so hard. Make a for, then inside make a setTimeout go to the next array.

jscheuer1
10-31-2010, 06:19 AM
http://www.burmees.nl/menu/bookextended.html

Nile
10-31-2010, 03:36 PM
@jscheuer1: I thought he ment that kind of flip book too - but then I thought it couldnt be because he said he searched google and the first results on google are flipbooks like that. I'm pretty sure he wants a flipbook like when you take Post-its and draw little stick figures over 1 millimeter on ever post it, then when you flip through it it looks like hes walking.

vwphillips
10-31-2010, 04:12 PM
http://www.vicsjavascripts.org.uk/PhotoBookIII/PhotoBookIII.htm

Nile
10-31-2010, 04:21 PM
Again, I'm pretty sure thats not what he is asking for.

fileserverdirect
10-31-2010, 04:31 PM
ugh, Nile is the only one who gets it. So anyways, I have an array set up with all the files in it. I am also using jquery, which may be helpful. Now I don't know javascript very well, so I'm going out on a limb here; I would know how to do this in php, but not in javascript\jquery. Structurally it would be like:



var imgs = new array("photo01.jpg","photo02.jpg","photo03.jpg");

for(i=0; i<imgs.length; i++) {
$("#flipbook").delay(500).src(imgs[i]);
}

#flipbook is <img id="flipbook" src="" />

Nile
10-31-2010, 04:48 PM
Yeah, give it a try.
Remember its new Array()

fileserverdirect
10-31-2010, 05:12 PM
Well, i did some googling and I came up with two solutions, but nether work:



html>
<head>
<title>flipbook</title>
<SCRIPT type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></SCRIPT>

</head>
<body>
<img id="flipbook" src="" />
<script type="text/javascript">
$(document).ready(function(){
imgs = new Array("photo01.jpg","photo02.jpg","photo04.jpg");
$.each(imgs, function(key, img) {
//$.delay(1000, function(){$("#flipbook").attr({src: img}); });
$("#flipbook").animate({"margin-top":"0px"},"1000",function(){$("#flipbook").attr({src: img}); });
});
});
</script>
</body>
</html>

I commented out the first one, the second one does not work either.Any help?

Nile
10-31-2010, 06:05 PM
Hmm this is weird, I tried:


<html>
<head>
<title>flipbook</title>
<SCRIPT type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></SCRIPT>

</head>
<body>
<img id="flipbook" src="" />
<script type="text/javascript">
$(document).ready(function(){
var imgs = new Array("images/image1.jpg","images/image2.jpg","images/image3.jpg", "images/image4.jpg", "images/image5.jpg", "images/image6.jpg", "images/image7.jpg", "images/image8.jpg", "images/image9.jpg");
$.each(imgs, function(key, img) {
setTimeout(function() { $("#flipbook").attr('src', imgs[key]) }, 1500);
});
});
</script>
</body>
</html>

But it just skips to image6 and stops... hmm

djr33
10-31-2010, 06:06 PM
You can do this using an animated gif. The problem is that it will load very slowly and the first time through it will play only as fast as it can load. If you only need 300ms that might actually work, but I'm not sure. Certainly it won't be 30 frames per second or anything like that. What happens with a gif, though, is that after it loads (slowly) that first time, it will loop at full speed.

I'm not recommending a gif, but I am guessing that there will be a parallel for JS: you can't play it back at full speed until it's loaded until the time between each frame allows for it to load one image per frame length. And on a slow connection (or server) that definitely won't work. On a fast connection, it might be fine some of the time.

Because of this, you have two options: either deal with it being slow for the first loop or preload everything.

The real question is how many images you will use, and how big those files will be. 100 isn't a huge amount, but it's significant, and unless they're small files (~10kb each), I wouldn't be confident it would load fast enough.

Of course you can try it, and any slideshow should work for this, ignoring the loading issue.

The alternatives which make a lot more sense to me are:
-flash
-embed a movie

Flash is probably the best solution here.


And you could even try a gif if that fits what you need.

Nile
10-31-2010, 06:33 PM
@djr33
In javascript, instead of waiting for the image to load it will show the image for 300 miliseconds with an X (I'm guessing you know how that works)

jscheuer1
10-31-2010, 06:41 PM
Your code 'worked' for me in Firefox. What's it supposed to do? I had a plain slideshow with no effects, a delay of 1 second between images, stopping at the last image.

But all of that seems a long way to go for just that. I'd do:


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>flipbook</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

</head>
<body>
<img id="flipbook" src="" alt="" />
<script type="text/javascript">
jQuery(function($){
var imgs = ['photo1.jpg', 'photo2.jpg', 'photo4.jpg'], im = $('#flipbook'), i = 0;
function flipthem(){
im.attr('src', imgs[i++]);
if(i < imgs.length){
setTimeout(flipthem, 1000);
}
}
flipthem();
});
</script>
</body>
</html>

But I'd probably want some effect(s) and a preload.

Do you want a flip book or just a slideshow?

Nile
10-31-2010, 06:46 PM
Okay, I'm pretty sure I know what he wants:
His client gave him 100 images that have lets say a ball at (1, 1). In the first one its at (1,1) at the second one it moves to (1, 2) at the third one it moves to (1, 3), and so on... Playing this all together you will see the ball moving.

The code works for you? It didnt for me.. =/

djr33
10-31-2010, 09:40 PM
Nile, yes it might display an X, but I was assuming a preloader (waiting to move to the next image until it was loaded). Without that it would of course not work.

fileserverdirect
10-31-2010, 10:31 PM
Okay, I'm pretty sure I know what he wants:
His client gave him 100 images that have lets say a ball at (1, 1). In the first one its at (1,1) at the second one it moves to (1, 2) at the third one it moves to (1, 3), and so on... Playing this all together you will see the ball moving.

That's pretty much what I want.
------------------

Ok, you guys are going to get mad at me but, when I read this:


Your code 'worked' for me in Firefox.

I was puzzled, Nile's wasn't working at all for me. I went back to mine and I realized that the .jpg endings did not match the .JPG endings on the files *face-palm*. I feel like an idiot, of all things I forgot the number 1 Apache rule: CaPiTaLiZaTiOn RuLeZ. Blech, my script worked fine after that:

$(document).ready(function(){
imgs = new Array("100_3380.JPG","100_3381.JPG","100_3382.JPG"); //these are the actual file names BTW
$.each(imgs, function(key, img) {
$("#flipbook").animate({"margin-top":"0px"},"400",function(){$("#flipbook").attr({src: img}); });
});
});
$.delay wasn't working so I set a css value to itself, with a duration of 400ms and a callback of setting the next image.
----

Nile, yes it might display an X, but I was assuming a preloader (waiting to move to the next image until it was loaded). Without that it would of course not work.
Yes, I now realize that I am running this flipbook with cached images, upon a force refresh only about half the image appears before it switches. It would need some sort of a preloader, perhaps a button to play the flipbook, then it would load all the images, then start. At the end a replay button would show up. Not really sure how to approach this, but yeah...

jscheuer1
11-01-2010, 11:38 AM
For example:


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>flipbook</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
(function($){
$.fn.extend({
flip: function(options){
options = $.extend({
imgs: null,
img: this,
// Default Options:
pause: 1000,
minpreload: 0
// End Defaults
}, options);
var imgs = options.imgs, imgsl = imgs.length, i = 0, img = options.img,
pause = options.pause, minpreload = options.minpreload? Math.min(imgsl, options.minpreload) : 0;
if(!imgs || imgs.constructor !== Array || imgsl < 2){
alert('imgs must be an array of at least 2 images');
return this;
}
function flipthem(){
img.attr('src', imgs[i]);
if(++i < imgsl){
setTimeout(flipthem, pause);
}
}
$.each(imgs, function(idx, im){
$(new Image()).bind('load error', function(){
if(idx + 1 === (minpreload || imgsl)){
flipthem();
}
}).attr('src', im);
});
return this;
}
});
})(jQuery);
</script>
<script type="text/javascript">
jQuery(function($){
$('#flipbook').flip({
imgs: ['photo1.jpg', 'photo2.jpg', 'photo4.jpg'], //Set array of images, must be at least 2 images. (required)
pause: 400, //Set pause between images. (defaults to 1000)
minpreload: 0 //Set minimum number of images that must be preloaded before show starts. Use 0 for all. (defaults to 0)
});
});
</script>
</head>
<body>
<img id="flipbook" src="" alt="" />
</body>
</html>

Either or both scripts can be made external. If you want a button:


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>flipbook</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
(function($){
$.fn.extend({
flip: function(options){
options = $.extend({
imgs: null,
img: this,
// Default Options:
pause: 1000,
minpreload: 0
// End Defaults
}, options);
var imgs = options.imgs, imgsl = imgs.length, i = 0, img = options.img,
pause = options.pause, minpreload = options.minpreload? Math.min(imgsl, options.minpreload) : 0;
if(!imgs || imgs.constructor !== Array || imgsl < 2){
alert('imgs must be an array of at least 2 images');
return this;
}
function flipthem(){
img.attr('src', imgs[i]);
if(++i < imgsl){
setTimeout(flipthem, pause);
}
}
$.each(imgs, function(idx, im){
$(new Image()).bind('load error', function(){
if(idx + 1 === (minpreload || imgsl)){
flipthem();
}
}).attr('src', im);
});
return this;
}
});
})(jQuery);
</script>
<script type="text/javascript">
jQuery(function($){
$('#mybutton').click(function(e){
e.preventDefault();
$('#flipbook').flip({
imgs: ['photo1.jpg', 'photo2.jpg', 'photo4.jpg'], //Set array of images, must be at least 2 images. (required)
pause: 400 //Set pause between images. (defaults to 1000)
});
});
});
</script>
</head>
<body>
<input id="mybutton" type="button" value="Go"><br>
<img id="flipbook" src="" alt="" />
</body>
</html>

It could as well be a link. The first script is unchanged.

Notice the minpreload option. If you have 100 images, depending upon their size and the length of the pause, it might be safe to set this at 10, or 50, etc., whatever. The images will continue to preload as the slideshow gets underway.

I added error to load as an event on the new Image() that triggers incrementing the c (short for count) variable because otherwise, if just one image is missing in IE, this can stop the entire show from loading.

fileserverdirect
11-02-2010, 04:26 AM
OMG, John, you are the best! I can't believe you wrote the whole plug-in just for this flipbook. I will eventually make a thread here on DD showing my client's site, giving credit to you for this devious little plugin. Unless of course you just copied and pasted this off of some snippet site (which this was such a specific request. so I digress).
Thanks Again.

jscheuer1
11-02-2010, 07:49 AM
I wrote it from what I'd previously posted. Converting something like that to a plugin is really pretty simple. You just have to remember that the meaning of this changes. Other than that, there are two basic ways I know of, extend the jQuery.fn object as I've done here, or write it as a property of said object.

I just noticed going back over things, I switched from using a variable c to using the $.each function's built in counting parameter (idx in the code). So the comments in my previous post about c actually refer to the use of idx.

I still haven't figured out how to - with something like this, take the document.ready (which in the code is expressed as):


jQuery(function($){

out of the second script and place it in the first.