Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 799
untitled Avatar asked Sep 12 '25 19:09

untitled


2 Answers

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;
like image 136
epascarello Avatar answered Sep 15 '25 08:09

epascarello


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);
like image 35
Louis Ricci Avatar answered Sep 15 '25 09:09

Louis Ricci