Duncan Malashock
Duncan Malashock

Reputation: 786

Loading all images before triggering JQuery Slideshow

I've modified Visual Idiot's Unslider (http://unslider.com/) to accommodate multiple-width slides based on image proportions, but in the process, I've encountered a bug which causes slides to load as tiny thumbnails (I think in the case where the images haven't loaded all the way). That's problem #1. So I'm trying to wait until all images are loaded. But I haven't found a way to do that successfully. That's problem #2.

Here is my added code inside the Unslider init() function:

_.init = function(el, o) {
  //  Check whether we're passing any options in to Unslider
  _.o = $.extend(_.o, o);

  _.el = el;
  _.ul = el.find(_.o.items);
  _.max = [el.outerWidth() | 0, el.outerHeight() | 0];
  _.max = [100, 100];
  _.li = _.ul.find(_.o.item).each(function(index) {
    var me = $(this);
    var an_image = me.find('img');
    an_image.load(function() {
      width = an_image[0].naturalWidth,
      height = an_image[0].naturalHeight;

      setSlideHeight(an_image, width, height, 300, 20);
      if ( an_image.parent().parent().is(":last-child") ) {

        _.el.css("width", 900);
      }
    })  

    //  Set the max values
    //if (width > _.max[0]) _.max[0] = width;
    //if (height > _.max[1]) _.max[1] = height;
  });

And here is my Ruby partial with a script inline for triggering Unslider when all the images are loaded.

<% if @page.cap_gallery_images.any? %>
  <script>
    $(document).ready(function() {
      var numLoaded = 0;
      var numToLoad = $('#gallery img').length;
      alert("To Load: " + numToLoad);
      $('#gallery img').load(function(){
        numLoaded += 1;
        alert("Loaded: " + numLoaded);
        if (numLoaded == numToLoad) {
          var gallery = $('#gallery').unslider(),
          data = gallery.data('unslider');
          data.to(0);
        }
      });
      $("#slidecontainer .slide a").click(function(e) {
        destination = $(this).parent().index();
        data.to(destination);
        e.preventDefault;
      });
      $(window).scroll(function() {
        checkGalleryAgainstLogo();
      });
      $(window).resize(function() {
        checkGalleryAgainstLogo();
      });
      checkGalleryAgainstLogo();
      $('#logo.small').addClass('white');
    });
  </script>
<% end %>

The issue is that it looks like the image loading handlers aren't all triggering. Look at it in context on the page I'm using it on: http://penumbra-2.herokuapp.com/education

Upvotes: 7

Views: 3502

Answers (6)

PeterKA
PeterKA

Reputation: 24638

The DOM ready event waits until the DOM is fully loaded before firing it's callback. However the load (window) event does not fire it's callback until the DOM and all images are fully loaded. This is the event you want to target:

$(window).load(function() { //Wait till DOM and images are fully loaded
                            //The run the code in here
    //**This is where/when to initialize the plugin.**
});

The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.

Upvotes: 1

Mircea Sandu
Mircea Sandu

Reputation: 926

There is a library built specifically for that it's what I always use when dealing with image loading because it also handles cached images. You can find it at https://github.com/desandro/imagesloaded

You can call it on the whole list of images and jQuery is optional when using it.

Upvotes: 1

Pankaj
Pankaj

Reputation: 99

The load event is sent to an element when it and all sub-elements have been completely loaded. .load is what you need. An advantage of using this is that you can attach this to a subset of DOM. If you have a images in a division like this

<div class="slider">
  <img src="image1.jpg"/>
  <img src="image2.jpg"/>
  <img src="image3.jpg"/>
</div>

Now you can use .load just on the slideshow container if all the images have loaded.

$('.slider img').load(function(){
  //Your code goes here
});

CAUTION : If you are using jQuery 1.8, this has been deprecated. You can use .on with appropriate arguments e.g .on('load', handler)

Upvotes: 2

guest271314
guest271314

Reputation: 1

Try this (pattern)

html

<!-- load images container, images with document, `display:none` -->
        <div id="slidecontainer" style="display:none;">
            <div class="slide"> <a href="#">
              <img alt="Chemistry-1" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/chemistry-1.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Hamilton" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/Hamilton.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Platinum6" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/platinum6.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Lectures-1-2" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/lectures-1-2.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Lenses-1-2" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/lenses-1-2.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Bromoil-1" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/bromoil-1.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Platinum2-1" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/platinum2-1.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Schaefer2" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/Schaefer2.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Classroom-1-2" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/classroom-1-2.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Dagbeq_web" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/dagbeq_web.jpg" />
            </a>

            </div>
            <div class="slide"> <a href="#">
              <img alt="Carbon_schaefer" class="center-slide" src="https://test-penumbra-images-cap.s3.amazonaws.com/uploads/Carbon_Schaefer.jpg" />
            </a>

            </div>
        </div>

    <div id="gallerycontainer">
        <div id="gallery" style="margin-top: 67px;"></div>
    </div>

js

// hold jquery `ready` `event`
$.holdReady(true);
// load images container, images into `slider` container
$("#gallery").load(document.location.href + " #slidecontainer", 
  function(data, textStatus, jqxhr) {
    // if all images loaded (11), document.ready, release `holdReady`
    return ($("#gallery img").length === 11 
              && $.isReady 
              && jqxhr.state() === "resolved"
            ? $.when($.holdReady(false)).done(function() {                    
                alert($.isReady);  
                $("#slidecontainer").css("display", "block");
                // images appended to document,                  
                // do (`slider`) stuff                   
              }) 
            : alert(!$.isReady) )
});

jsfiddle http://jsfiddle.net/guest271314/tLca3/

Upvotes: 1

serraosays
serraosays

Reputation: 7869

Regarding #2: I think youve made this too complex. You don't have to check on the individual img assets like you're doing; you really just want to know when the entire gallery has loaded, so make your life simple:

  $('#gallerycontainer').load(function(){
      $('#gallery').unslider();
    }
  });

Your might want to add the HTML into your question so people know how to target the jQuery:

<div id="gallerycontainer">
  <div id="gallery">
    <div id="slidecontainer">
      <div class="slide">
        <a href="#"><img /></a>
      </div>
    </div>
  </div>
</div>

Upvotes: 2

MacK
MacK

Reputation: 2191

I can see two different solutions on this, and depends on what's your objective.

On the code you're using $(document).ready(); which triggers when the DOM is ready, and not when the assets are totally downloaded, so makes sense to to detect when the image are loaded, but in this case I'd go for use the native Image() object and avoid using .load() as I found it extremely unreliable in several occasions, and as far as I know also sometimes it does not trigger perfectly if the images are loaded from the browser cache.

$('#gallery img').each(function() {
    var currentimage = new Image();
    currentimage.src = this.src;
    currentimage.onload = function(){
        numLoaded += 1;
        alert("Loaded: " + numLoaded);
        if (numLoaded == numToLoad) {
            var gallery = $('#gallery').unslider(),
            data = gallery.data('unslider');
            data.to(0);
        }
    };
});

Another solution (which I'll prefer to use here) is to use window.onload which triggers when your document and assets are fully downloaded, and you should use it in that way:

window.onload = function(){
    // Initialise your slider here
}

Upvotes: 1

Related Questions