Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

loading images to browser cache before slideshow

Posted on 2011-10-22
27
Medium Priority
?
447 Views
Last Modified: 2012-05-12
Hi,

I looking for some help on a bit of bespoke scripting to source a lot of images into batch slideshows.

The images don't sit locally as they're all from different sources/CDNs etc and jpegs

Is there a way in jquery to load image 1 and when the user hovers over it, a little animated 'loading' gif is overlayed until it has fetched the other images in the pool before it starts rotating through them at x speed?

Also, if an image doesn't load for some reason, can this be skipped?

So:

- page loads first image on page load
- upon hover, the script attempts to load the others
- once all images have either loaded or failed to load;
- rotate through the loaded ones at x speed (ignoring non-loaded images)


Huge Thanks for your help
0
Comment
Question by:dolythgoe
  • 14
  • 13
27 Comments
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37013424
Sounds to me we can start with

http://malsup.com/jquery/cycle/

you can add

$("#slideshow img").error(function() { $(this).remove()});

which will remove all images that cannot be found (possibly ending up with an empty slideshow)
0
 

Author Comment

by:dolythgoe
ID: 37015576
Hey, thanks for that.

I've got quite a few of these image 'stacks' on the page and what I'm most concerned about is the load order.

e.g. 10 stacks of 10 images - I would want to load:

The 1st image in each stack, the rest of the page.

Then upon hover over, request the other images in the stack (check for errors etc like you gave an example of above) and start rotating through.

Can this script do something like this?

Cheers
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37015924
Very likely.
What you are asking seems not really "can it do it" but more like "do it for me" which will mean (for me at least)
A) download the script
B) investigate how to lazy load with this particular script
C) create an example and test
D) Present the finished result
E) assist you with YOUR specific implementation since you are bound to have a different layout than I chose.

That is stuff I charge EUR 50 an hour for and being EE expert is unpaid from the good of our hearts.
Can you at least do steps A and C please?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:dolythgoe
ID: 37016194
Hi,

Well I just need some direction as I will piece this together myself. I did mean 'can it do' as it's important to at least understand the capabilities before experimenting.

My approach now is as follows:

- upon hover, request additonal images via ajax to a php file
- php file will echo back the images in the stack
- the jquery part will then take these urls and rotate through them

The ajax/php part will at least take care of the image 404 bit and sequential loading issue.

The jquery part is then just about transitional effects once it has loaded the images.

I've done the php file, now to the ajax hover calls :)

0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37017002
Here is a start.


<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
var caches = {};
function addImages(container) {
  var images = caches[container].imgArr;
  var cont = $("#"+container);
  cont.empty();
  for (var i=0, n=images.length;i<n;i++) {
    cont.append('<img src="'+images[i].src+'"/>')
  }
  // here you can start the slideshow for this container 
}
(function($) {

  // Argument 0 is the container, Argument1 is an array of image paths relative to the current page.
  $.preloadImages = function() {
    var container = arguments[0];
    var imageArr = arguments[1];
    var cache = caches[container] = {};   
    caches[container].imgArr  = [];
    caches[container].counter = 0;
    caches[container].errors  = 0;
    caches[container].loaded  = 0;
    for (var i = imageArr.length; i--;) {
      var cacheImage = $('<img/>');
      cacheImage.bind("load",function() { cache.imgArr.push(this); cache.loaded++; cache.counter++;if (cache.counter>=cache.imgArr.length) addImages(container) })
      cacheImage.bind("error",function() { cache.errors++; cache.counter++; if (cache.counter>=cache.imgArr.length) addImages(container)  })
      cacheImage.attr("src",imageArr[i]);
    }
    $(".slideshow").unbind("mouseenter"); // remove the mouseOver we defined in the onload
  }
})(jQuery);

$(document).ready(function() {
  // the stacks match the number of the div - div0 has stack 0 - this can be ajaxed or just present in the code. It is only text
  var stacks = [
   ["http://www.amnh.org/exhibitions/frogs/images/home/frogs_image.jpg","http://static.howstuffworks.com/gif/frog-1.jpg"]
  ];

  $(".slideshow").mouseenter(function() {
    var idx = this.id.replace("div","");
    jQuery.preloadImages(this.id,stacks[idx])
  });    

});
</script>  
</head>
<body>
<div id="div0" class="slideshow">
  <img src="http://www.amnh.org/exhibitions/frogs/images/home/frogs_image.jpg" />
</div>  
</body>
</html>

Open in new window

0
 

Author Comment

by:dolythgoe
ID: 37017132
Wow! Huge thanks for that - just running through it trying to dicipher ;)

So looking at this..var stacks is the place where I would output the sets of images in order to match the div id's?

I've been experimenting with the ajax part - well, psuedo coding if you like, what do you think of the approach below? Syntax is prob all wrong lol!

$(document).ready(function() {
  // the stacks match the number of the div - div0 has stack 0 - this can be ajaxed or just present in the code. It is only text
  var stacks = [];

  $(".slideshow").mouseenter(function() {
  
		//Get data needed to source the right images to feed the ajax request
		//Not sure about this, HTML 5 compliant, don't know if this will work in older browsers etc...need to test
		var dataString=this.getAttribute("data-string"); //or jquery equivalent
		
		//Set idx to that of the div
		var idx = this.id.replace("div","");
		
		//Call the php script for images
		$.ajax({
			type: "POST",
			url: "getimages.php",
			data: dataString,
			cache: true,
			success: function(imgdata)
			{
				//js equivalent of 
				//imgarr = implode(',', imgdata); <- unless better more direct method
				//Add the imgarr to the stacks array in position of idx
				$("#anotherdivid").html(html);
			}
		});
	
    
    jQuery.preloadImages(this.id,stacks[idx])
  });    

});
</script>  
</head>
<body>
<div id="div0" class="slideshow" data-string="var1=blah&var2=blah&var3=blah">
  <img src="http://www.amnh.org/exhibitions/frogs/images/home/frogs_image.jpg" />
 
</div>  
</body>
</html>

Open in new window



0
 

Author Comment

by:dolythgoe
ID: 37017134
Ah soz, ignore the $("#anotherdivid").html(html); bit
0
 

Author Comment

by:dolythgoe
ID: 37017145
And explode not implode! php file will echo urls seperated by commas
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37017193
try this instead

Result from php should be a comma delimited string of urls as in
img1.jpg,image2.gif,picture3.png

Open in new window

<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
var caches = {};
function addImages(container) {
  var images = caches[container].imgArr;
  var cont = $("#"+container);
  cont.empty();
  for (var i=0, n=images.length;i<n;i++) {
    cont.append('<img src="'+images[i].src+'"/>')
  }
  // here you can start the slideshow for this container 
}
(function($) {

  // Argument 0 is the container, Argument1 is an array of image paths relative to the current page.
  $.preloadImages = function() {
    var container = arguments[0];
    var cache = caches[container] = {};   
    caches[container].imgArr  = [];
    caches[container].stack = arguments[1];
    caches[container].counter = 0;
    caches[container].errors  = 0;
    caches[container].loaded  = 0;
    for (var i = imageArr.length; i--;) {
      var cacheImage = $('<img/>');
      cacheImage.bind("load",function() { cache.imgArr.push(this); cache.loaded++; cache.counter++;if (cache.counter>=cache.imgArr.length) addImages(container) })
      cacheImage.bind("error",function() { cache.errors++; cache.counter++; if (cache.counter>=cache.imgArr.length) addImages(container)  })
      cacheImage.attr("src",imageArr[i]);
    }
    $(".slideshow").unbind("mouseenter"); // remove the mouseOver we defined in the onload
  }
})(jQuery);

$(document).ready(function() {
  $(".slideshow").mouseenter(function() {
		var dataString=$(this).attr("data-string"); 
		var thisId = this.id; 
		//Set idx to that of the div
		var idx = thisId.replace("div","");
		//Call the php script for images
		$.ajax({
			type: "POST",
			url: "getimages.php",
			data: dataString,
			cache: true,
			success: function(imgdata) {
        // add the stack to the caches[divId], preloads and loads the div with the result			
			  jQuery.preloadImages(thisId,imgdata.split(",")); 
			}
		});
  });    
});
</script>  
</head>
<body>
<div id="div0" class="slideshow" data-string="var1=blah&var2=blah&var3=blah">
  <img src="http://www.amnh.org/exhibitions/frogs/images/home/frogs_image.jpg" />
 
</div>  
</body>
</html>

Open in new window

0
 

Author Comment

by:dolythgoe
ID: 37017242
Thanks - I recevied this error:

imageArr is not defined
[Break On This Error] for (var i = imageArr.length; i--;) {

I tried caches[container].imgArr.length but it didn't like that either!
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37017253
please try

success: function(imgdata) {
 alert(imgdata)
     // add the stack to the caches[divId], preloads and loads the div with the result                  
    jQuery.preloadImages(thisId,imgdata.split(","));
  }
0
 

Author Comment

by:dolythgoe
ID: 37017333
That's working ok, spits out the list of images delimited by ,

So the link up with the <div> data and the ajax request seem good..

I noticed it's imageArr when elsewhere it's imgArr but changing it didn't seem to work either :/

0
 
LVL 75

Accepted Solution

by:
Michel Plungjan earned 2000 total points
ID: 37017651
Euuw - lack of sleep last night.

Here
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
var caches = {};
function addImages(container) {
  var images = caches[container].imgArr;
  var cont = $("#"+container);
  cont.empty();
  for (var i=0, n=images.length;i<n;i++) {
    cont.append('<img src="'+images[i].src+'"/>')
  }
  // here you can start the slideshow for this container 
}
(function($) {

  // Argument 0 is the container, Argument1 is an array of image paths relative to the current page.
  $.preloadImages = function() {
    var container = arguments[0];
    var cache = caches[container] = {};   
    cache.imgArr  = []; // holds only images that loaded
    cache.stack = arguments[1]; // all image urls
    cache.counter = 0; // joint errors and loaded
    cache.errors  = 0; // only errors
    cache.loaded  = 0; // only loaded - same as .imgArr.length
    for (var i = cache.stack.length; i--;) {
      var cacheImage = $('<img/>');
      cacheImage.bind("load",function() { cache.imgArr.push(this); cache.loaded++; cache.counter++;if (cache.counter>=cache.stack.length) addImages(container) })
      cacheImage.bind("error",function() { cache.errors++; cache.counter++; if (cache.counter>=cache.stack.length) addImages(container)  })
      cacheImage.attr("src",cache.stack[i]);
    }
    $("#"+container).unbind("mouseenter"); // remove the mouseOver we defined in the onload
  }
})(jQuery);

$(document).ready(function() {
  $(".slideshow").mouseenter(function() {
		var dataString=$(this).attr("data-string"); 
		var thisId = this.id; 
		//Set idx to that of the div
		var idx = thisId.replace("div","");
		//Call the php script for images
		$.ajax({
			type: "POST",
			url: "getimages.php",
			data: dataString,
			cache: true,
			success: function(imgdata) {
        // add the stack to the caches[divId], preloads and loads the div with the result			
			  jQuery.preloadImages(thisId,imgdata.split(",")); 
			}
		});
  });    
});
</script>  
</head>
<body>
<div id="div0" class="slideshow" data-string="var1=blah&var2=blah&var3=blah">
  <img src="http://www.amnh.org/exhibitions/frogs/images/home/frogs_image.jpg" />
 
</div>  
</body>
</html>

Open in new window

0
 

Author Comment

by:dolythgoe
ID: 37017991
I know what that feels like!

Unfortunately, firebug gave me this:

imageArr is not defined
[Break On This Error] cacheImage.attr("src",imageArr[i]); 

Open in new window

Is that another one of those rogue imageArr's? :)
0
 
LVL 75

Assisted Solution

by:Michel Plungjan
Michel Plungjan earned 2000 total points
ID: 37018274
Yes

change
imageArr[i]

Open in new window

to
cache.stack[i]

Open in new window

0
 

Author Comment

by:dolythgoe
ID: 37018453
Awesome thanks again for all your help, much appreicated as I know it's not exactly easy stuff!!

Initial testing works when I mouseover an image when page refreshes but it will only act once - the functionality doesn't seem to repeat for other mouseovers. Could that be something to do with mouseenter tracking only once to class slideshow despite the several instances of it in the various divs?
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37018493
Not sure what you mean. I coded it so a Mouseover loads the stack for that div ONCE and the removes the stack loading mouse over since I could not imagine you wanted to load the same stack more than once.

0
 

Author Comment

by:dolythgoe
ID: 37018817
Yeah that's fine - I mean for all the different stacks. It loads one stack fine - any one of them on page reolad but if I move the mouse around over a few different ones it won't load any of those - only the first <div> to have the mouseover.

So I've got:

<div class="slideshow id=div0">
</div>
<div class="slideshow id=div1">
</div>
<div class="slideshow id=div2">
</div>
<div class="slideshow id=div3">
</div>
<div class="slideshow id=div4">
</div>
<div class="slideshow id=div5">
</div>
...more..

Open in new window


If I load the page and hover over...say...div4, it will load that stack but if I then move to any of the others, they don't respond.

Of course, like you said, it's only right to load one stack once.
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37018850
Aha then I misunderstood.
I know the problem - I unbind by class instead of by id
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37018909
Change
$(".slideshow").unbind("mouseenter");
To
$("#div"+idx).unbind("mouseenter");

I'll check it in about an hour

0
 

Author Comment

by:dolythgoe
ID: 37019007
Cool - that errors with:

idx is not defined
[Break On This Error] $("#div"+idx).unbind("mouseenter")

I guess need a way to pass that between functions?
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37019039
No I need to get to a real computer. Gimme 45

0
 
LVL 75

Assisted Solution

by:Michel Plungjan
Michel Plungjan earned 2000 total points
ID: 37019185
$("#"+container).unbind("mouseenter"); // remove the mouseOver we defined in the onload

0
 

Author Comment

by:dolythgoe
ID: 37019364
That's done it :)

Well, thanks so much again for going a few extra miles on this one.

I'll close this off and move onto the next phase of rotating through them on continued mouseover. I have some script written down and I''ll have a bash before troubling experts once more!

Cheers
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37019491
Great :)

for next time, it is ok to accept one comment as solution if the ones you are accepting are all from the same expert - saves you a lot of clicking :)
0
 

Author Comment

by:dolythgoe
ID: 37019540
I'd thought I'd highlight the corrections too for the good of the community :)!
0
 
LVL 75

Expert Comment

by:Michel Plungjan
ID: 37020222
Ah I thought you might, actually I already copied them to the main comment, because I can
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article demonstrates how to create a simple responsive confirmation dialog with Ok and Cancel buttons using HTML, CSS, jQuery and Promises
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…
Suggested Courses

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question