0

I am using html2canvas and jsPDF for PDF generation. The downloaded PDF should look like the preview of the document, but I am facing issues with the table layout. Specifically, the text in the table columns is not wrapping properly, causing the content to get cut off, and I'm unable to see the full text in those columns. I have attached an image of the table for reference. How can I resolve this issue to ensure the text wraps correctly within the columns?

check image here

Here is the code:

export const downloadComponentAsPDF = async (elementId, fileName) => {
  const contentArea = document.getElementById(elementId);

  if (contentArea) {
    try {
      const pdf = new jsPDF({
        orientation: 'portrait',
        unit: 'pt',
        format: 'a4',
      });

      const pdfWidth = pdf.internal.pageSize.getWidth();
      const pdfHeight = pdf.internal.pageSize.getHeight();
      const margin = 20;
      const elementMargin = 10;
      let positionY = margin;
      let currentPageHeight = pdfHeight - 2 * margin;

      // Group sections into rows based on layout
      const rows = [];
      let currentRow = [];
      let currentRowWidth = 0;

      const sections = Array.from(
        contentArea.querySelectorAll('.section, .non-section'),
      );

      sections.forEach(section => {
        const sectionWidth = parseInt(
          section.getAttribute('data-width') || '12',
        );

        if (currentRowWidth + sectionWidth > 12) {
          rows.push(currentRow);
          currentRow = [];
          currentRowWidth = 0;
        }

        currentRow.push(section);
        currentRowWidth += sectionWidth;
      });

      if (currentRow.length > 0) {
        rows.push(currentRow);
      }

      // Process each row and its sections in order
      for (const row of rows) {
        let rowHeight = 0;
        const rowSections = [];

        // Render sections in the current row
        for (const section of row) {
          const sectionWidth = parseInt(
            section.getAttribute('data-width') || '12',
          );
          const sectionCanvas = await html2canvas(section, {
            scale: 4,
            useCORS: true,
          });

          const imgData = sectionCanvas.toDataURL('image/png');
          const imgWidth = sectionCanvas.width;
          const imgHeight = sectionCanvas.height;

          const pdfImgWidth = (sectionWidth / 12) * (pdfWidth - 2 * margin);
          const pdfImgHeight = (pdfImgWidth * imgHeight) / imgWidth;

          rowHeight = Math.max(rowHeight, pdfImgHeight);
          rowSections.push({
            imgData,
            pdfImgWidth,
            pdfImgHeight,
            sectionWidth,
          });
        }

        // If row height exceeds current page height, create a new page
        if (positionY + rowHeight > currentPageHeight) {
          pdf.addPage();
          positionY = margin;
          currentPageHeight = pdfHeight - 2 * margin;
        }

        // Render the row in the PDF
        let positionX = margin;
        for (const rowSection of rowSections) {
          pdf.addImage(
            rowSection.imgData,
            'PNG',
            positionX,
            positionY,
            rowSection.pdfImgWidth,
            rowHeight,
          );

          positionX += rowSection.pdfImgWidth + elementMargin;
        }

        positionY += rowHeight + elementMargin;
        currentPageHeight -= rowHeight + elementMargin;
      }

      pdf.save(`${fileName}.pdf`);
    } catch (error) {
      console.error('Error generating PDF:', error);
    }
  }
};

Here’s the image showing how the table columns should look in the expected result.
Check image here

1 Answer 1

0

HTML to canvas is a conversion to pixels. And as such images do not have any word wrap.

There are pixels of words but they are just part of pixel scan lines that wrap one line of pixels at full width of the image.

Likewise PDF (and thus jsPDF) has no concept of wrapping plain lines nor spacing of tables.

You could try splitting lines by set maxWidth such as shown here Word wrap in generated PDF (using jsPDF)?

There is a plugin called jsPDF-AutoTable that can prepare HTML js data into a format acceptable for non wrapped PDF conversion. see https://github.com/JonatanPe/jsPDF-AutoTable

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.