untitled
untitled

Reputation: 405

Does a parent element with "display: none" cause child imgs to not load?

Currently, I'm using canvases to dynamically generate grayscale images with javascript. The grayscale code is as follows:

// Grayscale w canvas method
function grayscale(src)
{
    var canvasUrl = false;

    try
    {
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var imgObj = new Image();
        imgObj.src = src;
        canvas.width = imgObj.width;
        canvas.height = imgObj.height;
        ctx.drawImage(imgObj, 0, 0);
        var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
        for(var y = 0; y < imgPixels.height; y++){
            for(var x = 0; x < imgPixels.width; x++){
                var i = (y * 4) * imgPixels.width + x * 4;
                var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
                imgPixels.data[i] = avg;
                imgPixels.data[i + 1] = avg;
                imgPixels.data[i + 2] = avg;
            }
        }
        ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
        canvasUrl = canvas.toDataURL();
    }
    catch(err)
    {
        canvasUrl = false;
    }

    return canvasUrl;
}

In my code, my images are placed in a div. The div has the setting "display:none" until the javascript executes and finishes generating grayscale representations of all the images, at which point it sets the div to have "display: block".

This works most of the time but not all of the time. Occasionally, the div will not show up, because an error occurs on the following line:

var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);

error

Based on related questions here on SO, the general solution seems to be to use $(window).load(func); to run the grayscale generation code.

However, that is what I am doing:

<script type="text/javascript">
    var animateTime = 250;

    // On window load. This waits until images have loaded which is essential
    $(window).load(function(){
        // Fade in images so there isn't a color "pop" document load and then on window load
        $(".item img").animate({opacity:1},animateTime);

        // clone image
        $('.item img').each(function(){
            var el = $(this);
            el.css({"position":"absolute"}).wrap("<div class='img_wrapper' style='display: inline-block'>").clone().addClass('img_grayscale').css({"position":"absolute","z-index":"998","opacity":"0"}).insertBefore(el).queue(function(){
                var el = $(this);
                el.parent().css({"width":el.css("width"),"height":el.css("height")});
                el.dequeue();
            });
            this.src = grayscale(this.src);

            if(!this.src)
                alert('An error occurred.'); // handle the occasional DOM error...
        });

        // Fade image
        $('.item img').mouseover(function(){
            $(this).parent().find('img:first').stop().animate({opacity:1}, animateTime);
        })
        $('.img_grayscale').mouseout(function(){
            $(this).stop().animate({opacity:0}, animateTime);
        });
        $('.item').mouseover(function() {
            $(this).children('h3').css('display', 'block');
            $(this).children('h3').stop().animate({opacity:1}, animateTime);
        });
        $('.item').mouseout(function() {
            $(this).children('h3').css('display', 'none');
            $(this).children('h3').stop();
            $(this).children('h3').css('opacity', '0');
        });

        $("#loading").css('display', 'none'); // hide the loading GIF
        $(".outer_content_container").css('display', 'block');
        $(".outer_content_container").animate({opacity:1}, animateTime*4);
    });
</script>

Which leads me to think: could the fact that I am setting "display: none;" on the parent div containing the images be causing the browser to not load the images at all and proceed to call window.onload?

Upvotes: 4

Views: 910

Answers (2)

Louis Ricci
Louis Ricci

Reputation: 21116

canvas.height = imgObj.height;gagein

What's gagin?

imgObj.src = src;

Before that line use the image load method and wrap the rest of your function in it.

imgObj.addEventListener("load", function() {
    canvas.width = imgObj.width;
    canvas.height = imgObj.height;gagein
    ctx.drawImage(imgObj, 0, 0);
    var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
    for(var y = 0; y < imgPixels.height; y++){
        for(var x = 0; x < imgPixels.width; x++){
            var i = (y * 4) * imgPixels.width + x * 4;
            var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
            imgPixels.data[i] = avg;
            imgPixels.data[i + 1] = avg;
            imgPixels.data[i + 2] = avg;
        }
    }
    ctx.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    canvasUrl = canvas.toDataURL();
}, false);

Upvotes: 3

epascarello
epascarello

Reputation: 207557

Because you have a race condition, the width and height of the image is not set until the image is loaded. Use the onload event to know when you can read the dimensions.

    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    var imgObj = new Image();
    imgObj.onload = function() {
        //do the processing here
    };
    imgObj.src = src;

Upvotes: 4

Related Questions