Search code examples
javascripthtmlcsshtml2canvas

html2canvas renders blank image


I am trying out html2canvas for the first time for converting my html element to an image. However, it renders a blank image instead. Here is a reproducer:

<div id="target">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque quis eleifend elit. Donec lectus sem, scelerisque sit amet facilisis quis, gravida a lacus. Nunc at lorem egestas, gravida lorem quis, pulvinar ante. Quisque id tempus libero. Mauris hendrerit nunc risus, ac laoreet lectus gravida et. Nam euismod magna ac enim posuere sagittis. Fusce at egestas enim, eu hendrerit enim.
</div>

<button onclick="takeScreenShot()">to image</button>
const div = document.createElement(('div'));
div.innerHTML = '<h1>asd</h1>';
document.body.appendChild(div);
 
window.takeScreenShot = function() {
    html2canvas(div, {
        onrendered: function (canvas) {
            document.body.appendChild(canvas);
        },
        width:320,
        height:220
    });
}

jsfiddle

Somehow on removing the target div, it renders correctly. Any idea what I am doing wrong?

EDIT: I can see a number of workarounds here and I also discovered a few myself. What I am trying to understand is why this is happening so I avoid having such issues in my app?


Solution

  • UPDATE 23 Oct 2020: The problem was that there is a div with id="target" before the script. If that is renamed then the jsfiddle works successfully. It seems that something (possibly in jsfiddle) uses the id "target" temporarily and was picking up the wrong one. (moving the div with id target to below the script also worked, probably because the temporary target would have been found first in the DOM).

    Several attempts at debugging this were made and the info is kept here because the answer was accepted without the paragraph above and for completeness.

    If the div (which has the <h1.... code) is put before the script as HTML rather than being created by the script it is put onto the canvas successfully.

    Likewise, the div with id target can be put onto the canvas successfully.

    So this will work:

    <div id="div"><h1>asd</h1></div> 
    
    window.takeScreenShot = function() {
        html2canvas(document.getElementById('div), {
            onrendered: function (canvas) {
                document.body.appendChild(canvas);
            },
            width:320,
            height:220
        });
    }
    

    (this is not pretending to be a complete answer, but it is too long for a comment)

    UPDATE: I moved away from jsfiddle and instead put a complete example up on my own space so I know there is nothing else going on. See it on http://ahweb.org.uk/testhtml2canvas.html It seems to work.

    Here is the complete code. Seems familiar? It is the code from the question without extras (e.g. the stuff jsfiddle has to put in or other libraries that are invoked)

    And let's try it in a snippet

    <!DOCTYPE html>
    <html>
    <!-- https://stackoverflow.com/questions/64484937/html2canvas-renders-blank-image -->
    <head>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
    </head>
    <body>
    <div id="target">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque quis eleifend elit. Donec lectus sem, scelerisque sit amet facilisis quis, gravida a lacus. Nunc at lorem egestas, gravida lorem quis, pulvinar ante. Quisque id tempus libero. Mauris hendrerit nunc risus, ac laoreet lectus gravida et. Nam euismod magna ac enim posuere sagittis. Fusce at egestas enim, eu hendrerit enim.
    </div>
    <button onclick="takeScreenShot()">to image</button>
    <script>
    let div = document.createElement(('div'));
    div.innerHTML = '<h1>asd</h1>';
    document.body.appendChild(div);
     
    function takeScreenShot() {
        html2canvas(div, {
            onrendered: function (canvas) {
                document.body.appendChild(canvas);
            },
            width:320,
            height:220
        });
    }
    </script>
    </body>
    </html>

    Also, if the complete document is put into the HTML part of a jsfiddle, with nothing extra in the JS part, it works. So jsfiddle is probably exonerated and it is something in some other library that is interfering ... to be continued...