Search code examples
javascripthtmlcsshtml5-canvashtml2canvas

Use html2canvas to capture a page at a fixed width no matter the screen size


I use html2canvas to save a webpage as an image and i'd like to get the same results on a mobile and a PC. My webpage has a table that renders differently on a smaller screen (via CSS). I would like html2canvas to save the canvas as if the webpage is always on a PC screen. This way the table on the webpage will always look the same.

I currently have a workaround which temporarily sets the body width and viewport initial-scale to something larger before html2canvas runs, saves the webpage, then reverts back to the previous body width and viewport scale. The code I use is at the bottom of this post.

It mostly works but has a bad user experience because during the html2canvas operation the webpage will grow larger, pause for a bit (during the save) then revert back. Which doesn't look very good from the users point of view. Also, this doesn't always work for every mobile device.

Is there a better way to do this? Can I have some sort of off screen html that mirrors my on screen html but will always render as if its on a PC?

// adjust screen and viewport to allow all table elements to fit on the screen correctly
document.body.style.width = '1024px';
let viewport = document.querySelector("meta[name=viewport]");
let remembered_viewport = JSON.stringify(viewport.outerHTML)
viewport.setAttribute('content', 'width=device-width, initial-scale=2');

// use html2canvas to save the webpage
let tag = document.getElementById("all");
html2canvas(tag).then(function(canvas) {
    let link = document.createElement("a");
    link.download = filename.toLowerCase();
    canvas.toBlob( function(blob) {
            link.href = URL.createObjectURL(blob);
            link.click();
        }, 'image/jpg');
    });

// reset screen and viewport
document.body.style.width = "auto";
if (remembered_viewport.includes("initial-scale=0.5")) viewport.setAttribute('content', 'width=device-width, initial-scale=0.5');
if (remembered_viewport.includes("initial-scale=2")) viewport.setAttribute('content', 'width=device-width, initial-scale=2');
else viewport.setAttribute('content', 'width=device-width, initial-scale=1');

Thanks in advance, Jason.


Solution

  • Thanks to CBroe I did get it working using an off screen iframe. As follows:

    // capture my on screen html
    let html = document.documentElement.outerHTML;
    // create the iframe
    // there is css to push it off screen (ie. left: -1024px;)
    let iframe = document.createElement("iframe");
    iframe.style.width = "1024px";
    iframe.style.height = "100%";
    document.body.appendChild(iframe);
    // add html to iframe
    iframe.srcdoc = html;
    
    // wait for iframe to load
    iframe.addEventListener("load", () => {
       // use html2canvas to save the webpage
       html2canvas(iframe.contentWindow.document.body).then(function(canvas) {
         let filename = "image.jpg";
         let link = document.createElement("a");
         link.download = filename.toLowerCase();
         canvas.toBlob( function(blob) {
                link.href = URL.createObjectURL(blob);
                link.click();
            }, 'image/jpg');
         });
    });
    

    I do need to remove the iframe after the iframe is loaded AND the image is saved, but the basics appear to work without any odd on screen size changes.