72

I'm trying to use HTML2Canvas to render the contents of a div. Here is the code:

var htmlSource = $('#potenzial-page')[0];
    
$('#btn').on("click", function() {          
    
    html2canvas(htmlSource).then(function(canvas) {
        var img = canvas.toDataURL();
        window.open(img);
    });

});

I'm using v5 beta 3.

When this code runs, it only renders what is visible on the screen. The #potenzial-page div is essentially the entire page, minus the header and footer. All content in this div is visible by scrolling (there are some hidden elements, but I do not want the hidden elements visible in the image.)

I cannot find what's wrong or why it won't save the entire div. I should also note that it appears the image is as tall as the div but only partially visible.

To give an example of what I mean, here is a comparison:

Enter image description here

The left is how HTML2Canvas should render the div. The right shows how it renders when it runs the code above. The right image is what's visible in my browsers screen.

I did try adding the height option but it doesn't make a difference.

If I scroll to the very top of the page then run the script it will render the entire div as it should.

How do I render the div without having to scroll to the top?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
L84
  • 45,514
  • 58
  • 177
  • 257
  • Have you seen this solution in SO : "[Html2canvas converting overflowed content to image](https://stackoverflow.com/q/18012044/445600)" A workaround solution is proposed with setting overflow to visible then render then overflow hidden. – Devernay Stéphane Mar 25 '16 at 03:42
  • This probleme is solved : https://github.com/niklasvh/html2canvas/issues/1438#issuecomment-739244530 – zerbene May 07 '21 at 17:36

18 Answers18

60

I hope this helps you:

html2canvas(htmlSource, {scrollY: -window.scrollY})
    .then(function(canvas) {
        var img = canvas.toDataURL();
        window.open(img);
    });
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
44

A solution that worked for me was to add the following to my CSS content:

.html2canvas-container { width: 3000px !important; height: 3000px !important; }

It prevents html2canvas from limiting the rendering to the viewable area (which seems to be the default).

See here: Render off-screen elements #117

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jbgt
  • 1,586
  • 19
  • 24
16

I used window.scrollTo()in my case and it worked for me.

Below is sample code

$('#btn').on("click", function() {
    window.scrollTo(0,0);
    html2canvas(htmlSource).then(function(canvas) {
        var img = canvas.toDataURL();
        window.open(img);
    });
    window.scrollTo(0, document.body.scrollHeight || document.documentElement.scrollHeight);
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amit Anand
  • 265
  • 2
  • 6
12

I just did something like this and it worked for me:

html2canvas(document.querySelector("#capture2image"), {
            allowTaint: true,
            useCORS: true,
            logging: false,
            height: window.outerHeight + window.innerHeight,
            windowHeight: window.outerHeight + window.innerHeight, 
Ricky Levi
  • 7,298
  • 1
  • 57
  • 65
  • 1
    If you have a scrollable DIV, use `height: $('#wrapper')[0].scrollHeight, windowHeight: $('#wrapper')[0].scrollHeight,` to get the correct dimensions. – Avatar Nov 27 '22 at 16:07
  • this is even not taking the full height my container height is 7000 but it is showing data only few of them out of 24 list items I can see only 14 – Jagannath Swarnkar Dec 01 '22 at 13:04
  • @JagannathSwarnkar Try to see if the content actually loaded in its entire body before you run the above command, if it's loading only when you scroll etc ... if the data is there - it should take the whole page – Ricky Levi Dec 02 '22 at 13:21
  • This worked for me. I wanted to convert html to canvas, and it was not rendering the part which was not on the screen (the part which is only visible when we scroll horizontally). I did the following. ```html2canvas(document.getElementById("print"), { allowTaint: true, useCORS: true, logging: false, width: window.outerWidth + window.innerWidth, windowWidth: window.outerWidth + window.innerWidth, }).then``` – AgentNirmites Jan 13 '23 at 15:36
12

You can add in the scroll position as a variable in html2canvas which removes the need to scroll the page.

html2canvas(document.querySelector("#your-element"), {
        scrollX: 0,
        scrollY: 0
      }).then(function(canvas) {
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kaiser47
  • 174
  • 1
  • 4
  • Perfect. Thank you. – Libin Mar 19 '20 at 13:29
  • 2
    Not working as expected. Earlier it was capturing only the visible part, now it captures from the top (fine), but only some part equal to the height which is visible and rest as blank white. – kb0000 Jun 07 '20 at 08:30
3

enter image description here

If you have a height set to the div you want to turn to a canvas - you need to remove that before actually taking the snapshot. Otherwise it will just cut it off because of that height.

 $(".yourElemThatHasSomeHeightSet").css("height", "");

Then you will notice that scrolling down - will still cut your document. Simply do a:

$("html, body").scrollTop(0);

before taking the snapshot.

NSP
  • 41
  • 3
2

This is how I've achieved it in React.

The main problems were ratio and scale. If you do a quick window.devicePixelRatio, its default value is 2 which was causing the half image issue.

const printDocument = () => {
  const input = document.getElementById('divToPrint');
  const divHeight = input.clientHeight
  const divWidth = input.clientWidth
  const ratio = divHeight / divWidth;

  html2canvas(input, { scale: '1' }).then((canvas) => {
    const imgData = canvas.toDataURL('image/jpeg');
    const pdfDOC = new jsPDF("l", "mm", "a0"); //  use a4 for smaller page

    const width = pdfDOC.internal.pageSize.getWidth();
    let height = pdfDOC.internal.pageSize.getHeight();
    height = ratio * width;

    pdfDOC.addImage(imgData, 'JPEG', 0, 0, width - 20, height - 10);
    pdfDOC.save('summary.pdf');   //Download the rendered PDF.
  });
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Priyanshu Chauhan
  • 5,297
  • 5
  • 35
  • 34
1
  window.scrollTo(0,0);  

Add this works for me.

1

For people who don't want a hacky way for the scroll problem: dom-to-image

  1. you can scroll while you are snapshotting an image
  2. and it's much faster (70x according to this blog).

Blog: Here’s Why I’m replacing html2canvas With html-to-image in Our React App

In the blog, it mentions html-to-image. It is a fork of dom-2-image. I used dom-to-image (ancestor, original one).

var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then(function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bh_earth0
  • 2,537
  • 22
  • 24
1

The following code worked for me:

      window.scrollTo(0, 0);

      html2canvas(htmlRef, {
        scrollX: -window.scrollX,
        scrollY: -window.scrollY,
        windowWidth: document.documentElement.offsetWidth,
        windowHeight: htmlRef.scrollHeight,
      }).then((canvas) => {
        const img = new Image();

        const imgData = canvas
          .toDataURL("image/png")
          .replace("image/png", "image/octet-stream");

        const pdf = new jsPDF("p", "mm", "a4");
        const imgProps = pdf.getImageProperties(imgData);
        const pdfWidth = pdf.internal.pageSize.getWidth();
        const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
        pdf.addImage(imgData, "JPEG", 0, 0, pdfWidth, pdfHeight);
        pdf.save();
      });
Sai Teja T
  • 332
  • 2
  • 10
1

Use:

<div #potentialContainer id="potentialContainer" class="potentialContainer" style="height: auto;">
some large content here--------------------
</div>

import html2canvas from 'html2canvas';

downloadImage() {

html2canvas(document.querySelector('#potentialContainer'), {
  logging: true,
  allowTaint: false,
  useCORS: true,
  width: document.querySelector('#potentialContainer').scrollWidth,
  height: section.scrollHeight,
  scrollX: -window.scrollX,
  scrollY: -window.scrollY,
}).then((canvas) => {
  var imgWidth = 210;
  var pageHeight = 290;
  var imgHeight = canvas.height * imgWidth / canvas.width;
  var heightLeft = imgHeight;


  var doc = new jsPDF('p', 'mm');
  var position = 0;
  var pageData = canvas.toDataURL('image/jpeg', 1.0);
  var imgData = encodeURIComponent(pageData);
  doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
  doc.setLineWidth(5);
  doc.setDrawColor(255, 255, 255);
  doc.rect(0, 0, 210, 295);
  heightLeft -= pageHeight;

  while (heightLeft >= 0) {
    position = heightLeft - imgHeight;
    doc.addPage();
    doc.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
    doc.setLineWidth(5);
    doc.setDrawColor(255, 255, 255);
    doc.rect(0, 0, 210, 295);
    heightLeft -= pageHeight;
  }
  doc.save('file.pdf');

 });
 }

Note: It is important to add style height:auto

The above code will convert a large image to a multipage PDF document.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shiju
  • 51
  • 5
0

Another React approach...

On your submit button, on click, set the document height dynamically, and then call html2canvas using document.body as the first argument:

<button onClick={() => {
    var body = document.body,
    html = document.documentElement;

    var height = Math.max(body.scrollHeight, body.offsetHeight,
                          html.clientHeight, html.scrollHeight, html.offsetHeight);
    document.body.style.height = `${height}px`

    html2canvas(document.body).then(function (canvas) {
                    var imgData = canvas.toDataURL('image/pdf')
                    var doc = new jsPDF('p', 'mm', [canvas.width, canvas.height])
                    doc.addImage(imgData, 'PDF', 10, 10, canvas.width, canvas.height)
                    doc.save('name-of-pdf.pdf')
        });
    }}
>Submit</button>

This will set the html height of public/index.html which html2canvas seems to render from (i.e., not the "root" div).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul Sender
  • 376
  • 2
  • 19
0

This works for me:

  const input = document.getElementById('fragmentForPDF');
  
  // This row fixed problem
  input.parentNode.style.overflow = 'visible';

  html2canvas(input)...
Ruslan Valeev
  • 1,529
  • 13
  • 24
0
window.scrollTo(0, 0); // this will help to print if div hidden or on mobile screen

html2canvas(document.getElementById("my_div_img")).then(function (canvas) 
                 {
                    //for give white BG
                    var context = canvas.getContext('2d');
                    context.save();
                    context.globalCompositeOperation = 'destination-over';
                    context.fillStyle = "rgb(255, 255, 255)";
                    context.fillRect(0, 0, canvas.width, canvas.height);
                    context.restore();
                    var imgData = canvas.toDataURL('image/jpeg', 1);
                    //console.log(imgData);
}
ajmirani
  • 366
  • 3
  • 8
0

This worked for me:

html2canvas(el, {
    width: el.scrollWidth,
    height: el.scrollHeight,
})

See here for the source.

Aziza Kasenova
  • 1,501
  • 2
  • 10
  • 22
0
document.getElementById("dld_report").addEventListener("click", function() {
    // Make sure the area you want to take screenshot is visible in CSS
    document.querySelector('#boundary').style.overflow = 'visible'; 
     
    html2canvas(document.querySelector('#boundary'), {
      // Set the height of screenshot image same as page hieght
      height: window.outerHeight + window.innerHeight,
    }).then(function(canvas) {
        saveAs(canvas.toDataURL(), 'report.png');
    });
});
// dld_report -> button to trigger the screenshot

Set style overflow = "visible" and height were the key to make this happen.

Jaz Pin
  • 117
  • 1
  • 7
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 14 '22 at 07:24
0

FWIW: My biggest issue with this was the difference in rendering on a desktop vs. mobile. html2pdf would render the entire div on the desktop, but only what was visible on the screen on a mobile device. Explicitly setting the height and width of my canvas fixed the issue for me across the board. Because of responsiveness of mobile devices, and wanting continuity, I copy the content of my preview div into a hidden 'print' div and set my styles accordingly in a css file.

      function getPDF() {
         // Create an HTML5 Canvas, write the content of the Flyer div to the canvas, convert it to an image and use jspdf to display it
         $('#FlyerPrintCopy').html($('#FlyerContainer').html());
         var contentDiv = document.getElementById('FlyerPrintCopy');

         //A2 Paper Size (mm): 420 x 594 mm
         /*
          * With 72 DPI and standard margins:
               Adjusted pixel width = (420 / 25.4) * 72 - (2 * 72) ≈ 1075 pixels
               Adjusted pixel height = (594 / 25.4) * 72 - (2 * 72) ≈ 1528 pixels
          */
         var width = 1075;
         // Add 25px to account for the top margin
         var height = 1553;

         $('#FlyerPrintCopy').removeClass('d-none');
         
         // Use html2canvas to render the div content on the canvas
         // Make sure to set the width and height or it will only render the viewable content
         html2canvas(contentDiv, {
            width: width,
            height: height,
            x: 0,
            y: 0
         }).then(function (canvasImage) {
            var img = canvasImage.toDataURL("image/png");

            var doc = new jsPDF({
               unit: 'px',
               format: 'a4'
            });

            var widthScale = width * .375;
            var heightScale = height * .375;
            doc.addImage(img, 'PNG', 20, 25, widthScale, heightScale);
            doc.save('petflyer.pdf');
         });

         $('#FlyerPrintCopy').addClass('d-none');
      }
0

html2canvas doc said: windowWidth Window.innerWidth Window width to use when rendering Element, which may affect things like Media queries

windowHeight Window.innerHeight Window height to use when rendering Element, which may affect things like Media queries

html2canvas(element , {
        scrollX: -window.scrollX,
        scrollY: -window.scrollY,
        windowWidth: document.documentElement.offsetWidth,
        windowHeight: document.documentElement.offsetHeight
})