Search code examples
javascriptreactjspdfjspdfhtml2canvas

Border not aligned properly in PDF [Snippet attached]


I am making a very simple react application with ver minimal of content.

index.js:

<div className="App">
  <div id="printable-div">
    <h1>Generate PDF</h1>
    <p>Create a screenshot from the page, and put it in a PDF file.</p>
    <p style={{ color: "red" }}>
      *Open this page in new window and press the button.
    </p>
  </div>
  <br />
  <button id="print" onClick={printPDF}>
    PRINT
  </button>
</div>

Where here the div with id printable-div will gets printed.

I also applied a css for this like,

#printable-div {
  border: 2px solid #000;
  padding: 20px;
}

But while click on the button, the download of pdf happens whereas on opening the pdf file, the border is not aligned properly.

enter image description here

Also here, the order needs to be to the page but whereas it applied only to the div.

Libraries used:

-> jsPdf

-> html2canvas

And the code executed on click on the print button as follows,

  const printPDF = () => {
    const domElement = document.getElementById("printable-div");
    html2canvas(domElement).then((canvas) => {
      const imgData = canvas.toDataURL("image/png");
      const pdf = new jsPdf();
      pdf.addImage(imgData, "JPEG", 0, 0);
      pdf.save(`${new Date().toISOString()}.pdf`);
    });
  };

Complete working example:

Edit html2canvas-jspdf (forked)

Can anyone humbly help me to achieve the result of making the border properly aligned to the entire page? It is okay if the libraries used needs to be changed to other alternative..

Requirement:

The entire page needs to have border visible with all sides equal spacing and the content needs to be inside of the border..

enter image description here


Solution

  • I checked your codesandbox and it seems you'd already applied @Ihsan's solution, but to build on that solution I found that jsPDF has a fromHMTL function, so you can skip rendering to a canvas first.

    const printPDF = () => {
      const domElement = document.getElementById("printable-div");
      const doc = new jsPdf();
      doc.fromHTML(domElement, 10, 5); // position within rectangle
      doc.rect(5, 5, 200, 0.3);
      doc.rect(5, 5, 0.3, 285);
      doc.rect(5, 290, 200, 0.3);
      // doc.rect(5, 30, 200, 0.3); // this is the "middle" horizontal bar
      doc.rect(205, 5, 0.3, 285);
      doc.save(`${new Date().toISOString()}.pdf`);
    };
    

    I commented out the middle horizontal bar as this bar's vertical position just needs to be tweaked for where you want/need it.

    Edit

    Instead of a bunch of rectangles you can draw a single rectangle and stroke it to create the outer border, and use a line to fill in the horizontal "bar". IMO this reads a little more cleanly.

    const printPDF = () => {
      const domElement = document.getElementById("printable-div");
      const doc = new jsPdf();
    
      // Create border
      doc.rect(5, 5, 200, 285, "S").line(5, 45, 205, 45, "S");
    
      // Inject HTML
      doc.fromHTML(domElement, 10, 5);
    
      // Save out to PDF
      doc.save(`${new Date().toISOString()}.pdf`);
    };
    

    enter image description here

    In fairness I think Ihsan should get the bulk of the credit as this is basically their answer, I just got the content in there by a different means, and positioned the copied HTML.

    Edit border-not-aligned-properly-in-pdf-snippet-attached