Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Html2Canvas delay in rendering images and not in a sequence

I am having problems with Html2canvas render as i want to take multiple screenshots of an image and send the same to the selected contacts in a sequence but Html2canvas is rendering images in a delayed and unsequential way, which in return is not able to send the image to corresponding selected contact. Below is my code it is running successfully but the delay and unsequential output is creating a lot of problem.

function printCards(calle, eventID){
    var cards = new Array();

    var checkboxArray = $("input[name='contactsParty']:checked");

    $('#inviteContactName').html($(checkboxArray[0]).parent().prev().children('label').text());

        //  iterating selected checkboxes for invitation
        checkboxArray.each(function(index, value){


            //  getting name of next contact selected
            var name = $(checkboxArray[index+1]).parents().eq(1).find('label').text();


            //  Getting invitation card
            var invitationCard;
            $.when(invitationCard = getImage(name)).promise().done(function(){
                //  saving the printed invitation
                cards.push(invitationCard);
            });

        });

    return cards;   

}

//  printing invitation card with contact name
function getImage(name){

    var invitationCard = new Image();


        html2canvas($("#invitationData"), {
//          logging : true,
            onrendered: function(canvas) {
                //  For image`enter code here`
                var ctx=canvas.getContext("2d");
//              ctx.webkitImageSmoothingEnabled = false;
//              ctx.mozImageSmoothingEnabled = false;
                ctx.imageSmoothingEnabled = false;

                var convertedImage;
                $.when(convertedImage = canvas.toDataURL('image/jpg')).promise().done(function(){
                    invitationCard.src = convertedImage;
                    $('#inviteContactName').html(name);
                });  
//              setTimeout(function (){}, 500);
            }

        });

    return invitationCard;

}
like image 424
Abhishek Avatar asked Jul 06 '15 04:07

Abhishek


2 Answers

This shouldn't be an issue with Html2Canvas, rather the way you're loading base64 encoded images isn't using a callback.

Also, you're using promises in a "wonky" way, you're waiting on events that aren't asynchronous. So no wonder everything is in the wrong order.

canvas.toDataURL is executed synchronously, while assigning an Image object src is asynchronous.

As per the MDN page about images

var img = new Image();   // Create new img element
img.onload = function() {
    // image is loaded now
}
img.src = 'myImage.png'; // Set source path NOTE: this can be a base64 dataURL

Also, your getImage() function is not returning a $.deferred(), this means $.when() will execute immediately.

Here's some code that should fix it, I'm creating a promise that will be resolved when the image is loaded

function getImage(name){
    var promise = $.deferred();
    var invitationCard = new Image();
        html2canvas($("#invitationData"), {
            onrendered: function(canvas) {
                var ctx=canvas.getContext("2d");
                ctx.imageSmoothingEnabled = false;
                var convertedImage = canvas.toDataURL('image/jpg');
                invitationCard.onload = function () {
                    // here loading is done, resolve our promise
                    $('#inviteContactName').html(name);
                    // pass the loaded image along with the promise
                    promise.resolve(invitationCard);
                }
                invitationCard.src = convertedImage;
            }
        });
    return promise;
}

In your code calling getImage()

checkboxArray.each(function(index, value){
            //  getting name of next contact selected
            var name = $(checkboxArray[index+1]).parents().eq(1).find('label').text();
            //  Getting invitation card
            var invitationCard = getImage(name);
            $.when(invitationCard).done(function(image){
                //  promise is resolved, image is loaded and can be used
                cards.push(image);
            });
        });

I couldn't test your code specifically but I've had to manage plenty of images that had to be loaded after a series of canvas.toDataURL(). My problem when doing things in orderd was always the onload callback for Image objects, while Html2Canvas has worked correctly so far for me.

Also, the reason you see different behaviours on different browsers is due to the speed of execution and/or image caching. If the browser can load the image before you use it all goes well, but you shouldn't assume that, always use onload when creating images.

like image 85
Sosdoc Avatar answered Sep 24 '22 04:09

Sosdoc


This issue has been resolved in the upcoming release of html2canvas, as this issue has been raised earlier many times at developer's site. you just have to wait for the final release for production or you can try the beta version of it.

P.S - current release is for development purposes only and not for production. (This should be a comment but i dont have that much reputation.)

like image 43
Jen Avatar answered Sep 24 '22 04:09

Jen