6

I have an xml file which contains a list of images, I wish to load these images into a container and then apply masonry.

I have tried to wait for the images to load, http://masonry.desandro.com/demos/images.html. I have tried reload once each image has been added - http://masonry.desandro.com/docs/methods.html#reload

None of which are working.

Here is my code, I'm not sure where I am going wrong.

    $('.content').masonry();
    var elements = '';


    $.ajax({
        type: "GET",
        url: "/galleries/_archive/PhotoGallery.xml", // replace with absolute URL of your gallery's xml file
        dataType: "xml",
        success: function(xml) {
            jQuery(xml).find('img').each(function(i) {
               var location = "/galleries/_archive/"; // replace with absolute path to the directory that holds your images
               var url = jQuery(this).attr('src');
               var alt = jQuery(this).attr('alt');

            elements+= '<div class="image-div"><img class="round'+i+'" src="'+location+''+url+'" alt="'+alt+'"/></div>';

        });

        $('.content').append(elements).shuffle().masonry('reload');
        //$(".content .image-div").shuffle();
        }
     });

I have looked at this - jquery, masonry after append complete and this jQuery Masonry and Ajax Append Items?

I'm just wondering if on reload should the plugin wait for images to load? If so what is the syntax for this?

I also plan to hide the blocks (visibility:hidden), shuffle them into a random order and then masonry them then fade them in.

Any help would be amazing, I'm stumped. Thanks very much

Community
  • 1
  • 1
Tara Irvine
  • 823
  • 3
  • 22
  • 42

3 Answers3

0

jQuery .load() function will help to solve the problem.

Try with following code,

var totalImage = 0, imageCount = 0;
$.ajax({
    type: "GET",
    url: "/galleries/_archive/PhotoGallery.xml", // replace with absolute URL of your gallery's xml file
    dataType: "xml",
    success: function(xml) {
        totalImage = jQuery(xml).find("img").length;
        jQuery(xml).find('img').each(function(i) {
           var location = "/galleries/_archive/"; // replace with absolute path to the directory that holds your images
           var url = jQuery(this).attr('src');
           var alt = jQuery(this).attr('alt');

        elements+= '<div class="image-div"><img class="round'+i+'" src="'+location+''+url+'" alt="'+alt+'"/></div>';

    });

    $('.content').append(elements).shuffle();

    $('.image-div img').load(function() {
      imageCount++;
      if(totalImage == imageCount){
        $('.content').masonry('reload');
      }
});

I created totalImage and imageCount variable. On image load event I checked all the images are load complete. If totalImage and imageCount is same means all are load completed then I called masonry('reload') function.

sureshunivers
  • 1,683
  • 10
  • 26
  • Thanks I feel we're getting there, Here is a test page based on this solution - http://underwaterpistol.co.uk/test/index.html, pity stuff bounces when it's first loaded, is there anyway to only load 10 or 15 images at a time? I was thinking of adding visibility:hidden to the images and when the page has loaded add visibility:visible? is this the best way to stop the jump on load? Thanks so much for the help – Tara Irvine Sep 27 '12 at 19:28
  • Yes, best way using visibility:hidden / visibility:visible or display:none / display:initial for displaying images after load complete to avoid jump – sureshunivers Oct 03 '12 at 09:39
0

It looks like Masonry is operating on the DOM before the images are fully loaded. Use the imagesLoaded method that comes with Masonry to fix this:

Edit: Loads images in chunks, each chunk becoming visible when its images are fully loaded:

CSS

.hidden {
    display: none;
}

JavaScript

/*
 * Splits an array into subarrays of length "len".
 *
 * see: http://stackoverflow.com/a/11764168/159570
 */
function chunk(arr, len) {
    var chunks = [];
    var i = 0;
    var n = arr.length;
    while (i < n) {
        chunks.push(arr.slice(i, i += len));
    }
    return chunks;
}

var chunkSize = 10;    // images per chunk
var $content = $('.content').masonry();
$.ajax({
    type: "GET",
    url: "/galleries/_archive/PhotoGallery.xml",
    dataType: "xml",
    success: function(xml) {
        var allImages = $(xml).find('img').get();
        var imageArrayChunks = chunk(allImages, chunkSize);
        $.each(imageArrayChunks, function(i, imageArray) {
            var elements = '';
            $.each(imageArray, function(j, image) {
                var location = "/galleries/_archive/";
                var $image = $(image);
                var url = $image.attr('src');
                var alt = $image.attr('alt');
                var index = i*j + j;    // original unchunked index
                elements += '<div class="image-div hidden"><img class="round'+index+'" src="'+location+url+'" alt="'+alt+'"/></div>';
            });
            $content.append(elements).shuffle();
            $content.imagesLoaded(function(images) {
                $content.masonry('reload');
                $(images).parent().removeClass('hidden');
            });
            console.log('Chunk #'+i+' loaded...');
        });
    }
});
Joe Coder
  • 4,136
  • 26
  • 38
  • Thanks for the answer this is looking good but it's not loading nicely http://underwaterpistol.co.uk/test/three.html for me the first few times it's loading all at once and then sorts itself out, again I need a lazy load of 10-15 images at a time, is this possible? Thanks again for the help. – Tara Irvine Sep 27 '12 at 19:42
  • Just to clarify: you'd like 10-15 images to load, then appear at once, then begin loading the next batch, etc...? Or would you like them ALL to appear at the same time? – Joe Coder Sep 27 '12 at 22:50
  • I'm assuming the first one. Let me know if you want something different :) – Joe Coder Sep 28 '12 at 01:38
  • Your current web page is broken because the ` – Joe Coder Sep 28 '12 at 05:27
  • Thanks everyone for the answers, these answers are a great insight to how this can be accomplished – Tara Irvine Oct 01 '12 at 19:36
0

If you can store the height and width of each element inside your XML file. You can utilize those dimensions in your append statement. Doing so will allow masonry to work WITHOUT waiting for images to load in the browser. This way the browser wont have to 'reflow' the layout after the images are loaded, resulting in a smoother experience (less "janking" or bouncing) and faster perceived page load.

Plus its damn simple to implement, (especially considering you have to generate the XML file somehow anyways).

var elements = '';

$.ajax({
    type: "GET",
    url: "/galleries/_archive/PhotoGallery.xml", // replace with absolute URL of your gallery's xml file
    dataType: "xml",
    success: function(xml) {
        jQuery(xml).find('img').each(function(i) {
           var location = "/galleries/_archive/"; // replace with absolute path to the directory that holds your images

           var that= jQuery(this),
               url = that.attr('src'),
               alt = that.attr('alt'),
               h   = that.attr('height'),
               w   = that.attr('width');

        elements+= '<div class="image-div"><img class="round'+i+'" src="'+location+''+url+'" alt="'+alt+'" height="'+h+'" width="'+w+'"/></div>';

    });

    $('.content').append(elements).shuffle().masonry();
    }
 });

Just for fun:

CSS

.content img{
     opacity:0;
     -moz-transition:opacity 1s;
     -webkit-transition:opacity 1s;
     transition:opacity 1s;
}

.content .loadedImg{
     opacity:1;
}

JS

$('.content').on('load', 'img', function(){
     $(this).addClass('loadedImg');
});

In theory images will now fade in real nice once they are fully loaded in css3 supported browsers.

Fresheyeball
  • 28,195
  • 19
  • 94
  • 160