parallax / jsPDF

Client-side JavaScript PDF generation for everyone.
https://parall.ax/products/jspdf
MIT License
28.98k stars 4.64k forks source link

Manual pagination of PDF : html or html2canvas #3754

Open dshakya opened 1 month ago

dshakya commented 1 month ago

I create a Nodelist of sections in html by using querySelectAll and then iterate through it to generate image. I then create pages depending on the element height, finally saving it as PDF. It works well but it takes a long time. I used this method instead of the html plugin because it cut off the images and text between pages and I couldn't find documentation on how to use manual pagination with the html plugin. I can just turn the automatic pagination off but then the layout goes everywhere.

Because canvas2html creates iFrame in the DOM while converting to PDF, it takes a long time as I have about 20 sections to convert to image, add to doc and then save it. Is there a way to improve this workflow for faster rendering of the pdf? I couldn't use the web worker as there is DOM manipulation and it freezes the main UI thread while generating the PDF. I kind of got away by using the setTimeout to show the indeterminate progress bar but still very slow.

Is there a way to handle pagination a bit better using the manual way or while using the html plugin?

function generatePDF() {
  const doc = new jsPDF('p', 'mm', 'a4', true);
  const reportContainer = document.querySelector('#Report');
  const elements = reportContainer.querySelectorAll('section'); 
  let currentPage = 1;
  let yPos = 10;

  var margins = {
    top: 10,
    bottom: 10,
    left: 10,
    width: 210,
  };

  let pageno = 0;

  //Add header information
  html2canvas(elements[0] as HTMLElement, { scale: 3 }).then((canvas) => {
    const imgData = canvas.toDataURL('image/png');
    var width = margins.width - margins.left * 2;
    var height = (canvas.height * width) / canvas.width;
    doc.addImage(imgData, 'PNG', margins.left, yPos, width, height);
    yPos += height + 5;

    //Add report content
    setTimeout(() => {
      for (let i = 1; i < elements.length; i++) {
        html2canvas(elements[i] as HTMLElement, { scale: 3 }).then((canvas) => {
          const imgData = canvas.toDataURL('image/png');
          var width = margins.width - margins.left * 2;
          var height = (canvas.height * width) / canvas.width;

          if (yPos + height > 297) {
            doc.setFontSize(10);
            doc.text('Page ' + String(pageno + 1), margins.width / 2, 292, {
              align: 'center',
            });
            pageno++;

            doc.addPage();
            yPos = margins.top;
            currentPage++;
          }

          doc.addImage(imgData, 'PNG', margins.left, yPos, width, height); 
          yPos += height + 5;

          if (i === elements.length - 1) {
            doc.setFontSize(10);
            doc.text('Page ' + String(pageno + 1), margins.width / 2, 292, {
              align: 'center',
            });
            doc.save('Report.pdf');
          }
        });
      }
    }, 1000);
  });
}
susu-sama commented 1 month ago

dalao,怎么开启分页呀

susu-sama commented 1 month ago

function handleClick() { deviceReportsLazy.value = true const exprtCanvas = exportMe.value domToPng(exprtCanvas, {}).then(canvas => { const img = new Image() img.src = canvas let contentWidth, contentHeight img.onload = function () { contentWidth = img.width contentHeight = img.height const pageHeight = (contentWidth / 595.28) 1000 let leftHeight = contentHeight let position = 0 const imgWidth = 555.28 const imgHeight = (555.28 / contentWidth) contentHeight const pdf = new jsPDF('', 'pt', 'a4', true) if (leftHeight < pageHeight) { pdf.addImage(canvas, 'JPEG', 20, 0, imgWidth, imgHeight) } else { while (leftHeight > 0) { pdf.addImage(canvas, 'JPEG', 20, position, imgWidth, imgHeight) leftHeight -= pageHeight position -= 841.89 if (leftHeight > 0) { pdf.addPage() } } } pdf.save(${t('health.reportName')}.pdf) ElNotification({ title: t('common.form.tip'), message: t('common.text.success'), type: 'success', duration: 2000 }) deviceReportsLazy.value = false } }) }

susu-sama commented 1 month ago

我是这样写的,但是内容会被截断,有没有办法可以使动态的div容器不被截断