-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Description
I am using jsPDF + html2canvas to create a PDF document. However, I am encountering an issue where the content breaks when transitioning from one page to the next, especially since we are dealing with a substantial amount of content for conversion.


Facing this issue on all Mobile devices (IOS/Android)
Code Reference
async printBodyAsPDF(content) {
if (this.appUtility?.isMobileAppView() && this.appUtility?.isPageEligibleForPrintInMobile()) {
let nodes = content.querySelectorAll(".al-print-only");
if (nodes && nodes.length > 0) {
[].forEach.call(nodes, (ele) => {
ele.classList.remove("al-print-only");
});
}
// Adds float:right !important to the .al-w100 class dynamically
const style = document.createElement('style');
style.id = 'af-print-w100';
style.innerHTML = .al-w100 { float: none !important; }
;
document.head.appendChild(style);
// fix words spacing issue in IOS mobile app
if (this.appUtility.isIOS()) {
const styleelm = document.createElement('style');
styleelm.id = 'letter-spacing-fix';
// Add the CSS rule to the style element
styleelm.innerHTML = 'b, strong { letter-spacing: 0.02em !important; }';
document.head.appendChild(styleelm);
}
try {
// Render the desired element to canvas
const canvas = await html2canvas(content, { scale: 2 });
const imgData = canvas.toDataURL("image/png");
const pdf = new (window as any).jspdf.jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4',
putOnlyUsedFonts: true,
floatPrecision: 16,
});
// PDF page size in mm (A4)
const pdfWidth = 210;
const pdfHeight = 297;
// Canvas size in px
const imgWidth = pdfWidth;
let imgHeight = (canvas.height * pdfWidth) / canvas.width;
let remainingHeight = imgHeight;
// If content fits on one page
if (imgHeight <= pdfHeight) {
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
} else {
// Multi-page logic
let pageHeight = pdfHeight;
let pageCanvas = document.createElement("canvas");
let pageCtx = pageCanvas.getContext("2d");
let sX = 0, sY = 0, sWidth = canvas.width, sHeight = (canvas.width * pageHeight) / pdfWidth;
while (remainingHeight > 0) {
pageCanvas.width = canvas.width;
pageCanvas.height = Math.min(sHeight, canvas.height - sY);
pageCtx.clearRect(0, 0, pageCanvas.width, pageCanvas.height);
pageCtx.drawImage(canvas, sX, sY, sWidth, pageCanvas.height, 0, 0, sWidth, pageCanvas.height);
let pageImgData = pageCanvas.toDataURL("image/png");
pdf.addImage(pageImgData, "PNG", 0, 0, imgWidth, (pageCanvas.height * pdfWidth) / canvas.width);
remainingHeight -= pageHeight;
sY += sHeight;
if (remainingHeight > 0) {
pdf.addPage();
}
}
}
if (this.appUtility.isIOS()) {
// Save PDF after a short delay to ensure all resources are loaded
const currentDate = new Date();
const pageUrl = window.location.href;
const current_awl_page = this.appUtility.getPageName(pageUrl);
const filename = `${current_awl_page}_${currentDate.getFullYear()}_${currentDate.getMonth() + 1}_${currentDate.getDate()}_${currentDate.getHours()}_${currentDate.getMinutes()}_${currentDate.getSeconds()}.pdf`;
pdf.save(filename);
this.hideShowPDFLoader = false;
} else {
// Generate PDF as Blob
let blobUrl = pdf.output('bloburl');
window.open(blobUrl, "_blank");
// Added timer to clean browser memory
setTimeout(() => {
URL.revokeObjectURL(blobUrl.toString());
}, 5000);
// Hide the print loader
this.hideShowPDFLoader = false;
// show open as PDF button again
if (content) {
content.classList.add("al-print-only");
}
const allNode = document.querySelectorAll("body > *");
if (allNode && allNode.length > 0) {
[].forEach.call(allNode, (ele) => {
ele.classList.remove("al-print-no");
});
}
const lightBoxEle = document.querySelectorAll(".al-print-light-box");
[].forEach.call(lightBoxEle, (ele) => {
ele.remove();
});
// remove float:right !important to the .al-w100 class style
let styleTag = document.getElementById('af-print-w100');
if (styleTag) {
styleTag.remove();
}
let elm = document.getElementById('letter-spacing-fix');
if (elm) {
elm.remove();
}
}
} finally {
}
}
}