html2canvas wait for images to load

10,415

So since you're using remotes images you can use the following fix doing some modifications in your script:

function getPNGBase64forHtml() {
    var imageString;

    html2canvas(document.body, {
        useCORS: true,
        logging : true, //Enable log (use Web Console for get Errors and Warnings)
        proxy :"html2canvasproxy.php",
        onrendered: function(canvas) {
            var img = new Image();
            img.onload = function() {
                img.onload = null;
                document.body.appendChild(img);
            };

            img.onerror = function() {
                img.onerror = null;
                if(window.console.log) {
                    window.console.log("Not loaded image from canvas.toDataURL");
                } else {
                    alert("Not loaded image from canvas.toDataURL");
                }
            };

            imageString = canvas.toDataURL('image/png');
        }
    });

    return imageString;
}

If you are using php then the proxy setting must use the following script: html2canvas-php-proxy

Otherwise with .NET projects you can use these script resources:

html2canvas proxy with asp-classic - vb html2canvas proxy with asp.net - csharp

If you decided to use local images this bug will not appear.

Hope it works for you, here is the original thread for this html2canvas bug https://github.com/niklasvh/html2canvas/issues/145

Share:
10,415
Cserny
Author by

Cserny

Updated on June 04, 2022

Comments

  • Cserny
    Cserny almost 2 years

    I'm having this problem for some time ow and I can't seem to find a solution.

    I'm using the latest html2canvas js plugin to take a screenshot of chart made with flotcharts and then submit the base64 screenshot via a hidden input. The problem is the div with the chart also has some images and html2canvas return a base64 string before the images are loaded. I can put a setTimeout on the submit untill they are loaded but apparently chrome opens the page where I submitted as a popup (which is really not ok cause our clients don't know how allow popups). So this is what I tried but the images are not preloaded (because of the async nature of html2canvas)

    function getPNGBase64forHtml($container) {
        var imageString;
    
        html2canvas($container, {
            useCORS: true,
            onrendered: function(canvas) {
                imageString = canvas.toDataURL('image/png');
            }
        });
    
        return imageString;
    }
    

    And also this (this works ok but it doesn't load the images in time):

    function getPNGBase64forHtml($container) {
        var h2canvas = html2canvas($container);
        var queue = h2canvas.parse();
        var canvas = h2canvas.render(queue);
    
        return canvas.toDataURL('image/png');
    }
    

    So the problem is with waiting till the images are loaded in html2canvas then exeuting the rest of my stuff. If anyone can please help, that would be very much appreciated, I bow to you kind sirs and madams! :)

    Edit:

    Here is the html of the part that I capture, this all is in a print-container div thats all. The arrow (only one is showed) in the timeline-prognose doesn't get captured cause it's a image, everything else does:

    <div id="timeline-outer-container">
        <div id="timeline-container" class="flot-container">
            <div id="timeline-chart" class="flot-chart">
                <canvas class="flot-base" width="888" height="335" ></canvas>
                <div class="flot-text" >
                    <div class="flot-x-axis flot-x1-axis xAxis x1Axis">
                        <div class="flot-tick-label tickLabel" >Q1</div>
                        <div class="flot-tick-label tickLabel">Q2</div>
                        ...
                    </div>
                    <div class="flot-y-axis flot-y1-axis yAxis y1Axis">
                        <div class="flot-tick-label tickLabel">75</div>
                        <div class="flot-tick-label tickLabel">100</div>
                        ...
                    </div>
                </div>
                <canvas class="flot-overlay" width="888" height="335"></canvas>
                <div class="axis-label xaxis">Zeitraum</div>
                <div class="axis-label yaxis rotate-90">Anzahl</div>
                <div id="zoom-out-button" class="timeline-zoom-button"><i class="fa fa-zoom-out"></i></div>
                <div id="zoom-in-button" class="timeline-zoom-button"><i class="fa fa-zoom-in"></i></div>
                <div id="zoom-default-button" class="timeline-zoom-button"><i class="fa fa-repeat"></i></div>
            </div>
        </div>
    </div>
    
    <div id="timeline-prognose">
        <img id="timeline-arrow-up" class="timeline-arrows" src="/portal//images/arrows/up.png" alt="">
        <img id="timeline-arrow-down" class="timeline-arrows" src="/portal//images/arrows/down.png" alt="">
    </div>
    
  • Cserny
    Cserny over 9 years
    the images are local, the usecors flag is not necessary, i was just testing some stuf, so the problem is i need to wait for the images or preload them somehow
  • Grungondola
    Grungondola over 7 years
    setting the canvas handling in the onrendered variable tells it to process it after rendering all of the images. I use this library the same way as in this answer.