Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bytes received and bytes total of images via Javascript/jQuery

I'm working on a Javascript/jQuery powered image preloader, and have hit a bit of a snag. While as of currently it provides the progress based on loaded_images / total_images, this is not very accurate given a page could have a thousand 1kB images, and a single 1MB image.

I'm looking for a way to incorporate filesize into the progress calculations. Now, I've looked into some (cross browser compatible) tricks at capturing the filesize of a given image, and it seems that Ajax requests for Content-Length were the most reliable (in terms of accuracy) like so:

var imageSizeTotal = 0;
var ajaxReqest = $.ajax({
    type: 'HEAD',
    url: 'path/to/image',
    success: function(message){
        imageSizeTotal += parseInt(ajaxRequest.getResponseHeader('Content-Length'));
    }
});

Now, I find this method to be quite useful, as I can provide a status message of Initializing while the necessary requests are taking place. However my issue now is two-fold:

  1. Is there any way possible to capture the bytes loaded of a given image object, perhaps using setInterval() to periodically check? Otherwise, I'm sort of back at the issue of the progress indicator hanging on large files.
  2. How can I force the actual progress calculator, etc., portion of the script to wait until the necessary Ajax requests are completed (displaying Initializing or whatever), so it can go ahead with the loading?

Also, here's the script I currently use, which again, calculates progress based on the number of images, regardless of filesize or bytes received.

var preloaderTotal = 0;
var preloaderLoaded = 0;
var preloaderCurrent = null;

$('#preloaderCurtain')
    .bind('preloaderStart', function(){
        $(this)
            .show();
        $('*')
            .filter(function(e){
                if($(this).css('background-image') != 'none'){
                    preloaderTotal++;
                    return true;
                }
            })
            .each(function(index){
                preloaderCurrent = new Image();
                preloaderCurrent.src = $(this).css('background-image').slice(5, -2);
                preloaderCurrent.onload = function(e){
                    preloaderLoaded++;
                    if(preloaderLoaded == preloaderTotal - 1){
                        $('#preloaderCurtain')
                            .trigger('preloaderComplete')
                    }
                    $('#preloaderCurtain')
                        .trigger('preloaderProgress')
                };
            });
    })
    .bind('preloaderComplete', function(){
        $(this)
            .fadeOut(500)
        startAnimation();
    })
    .bind('preloaderProgress', function(e){
        $('#preloaderProgress')
            .css('opacity', 0.25 + (preloaderLoaded / preloaderTotal))
            .text(Math.floor((preloaderLoaded / preloaderTotal) * 100) + '%');
    })
    .trigger('preloaderStart');

Hopefully I'll be able to turn this into a plugin, once I work the bugs out of it.

like image 502
Dan Lugg Avatar asked Jan 16 '11 22:01

Dan Lugg


1 Answers

It looks like a similar question was asked and answered here:

XmlHttpRequest.responseText while loading (readyState==3) in Chrome

and here:

Comet Jetty/Tomcat, having some browser issues with Firefox and Chrome

Basically - .responseText.length for Firefox and iPhone, .responseBody.length for IE, WebSockets for Chrome.

The second thread suggests bayeux/dojo encapsulate all this for you into a higher-level API so you don't have to write it yourself.

like image 83
Chris Moschini Avatar answered Nov 03 '22 10:11

Chris Moschini