I have even added some delay on mobile devices to give time to process, change the image format to reduce processing effort and resolution size, I have change the viewport and 10% of the times works and the rest 90% doesn't work, as you can see I have added console.logs to debug and usually the last log is right prior to do the canvas capture or while is doing the capture, here is my code, any suggestion?
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script>
document.getElementById('generate-pdf').addEventListener('click', function() {
const isMobile = screen.width < 1024; // Check if the device is mobile
if (isMobile) {
// Temporarily change the viewport for mobile devices to width=800
const originalViewportContent = document.querySelector('meta[name="viewport"]').getAttribute('content');
document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=800');
console.log("Viewport temporarily set to width=800 for mobile.");
}
console.log("Starting PDF generation...");
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'pt', 'a4'); // A4 size PDF
// Select the div content
const content = document.getElementById('pdf-content');
console.log("PDF content selected.");
// Get all elements you want to exclude (e.g., buttons with class 'exclude')
const elementsToExclude = content.querySelectorAll('.exclude');
console.log("Elements to exclude:", elementsToExclude);
// Temporarily hide the excluded elements
elementsToExclude.forEach(function(el) {
el.style.display = 'none';
});
console.log("Excluded elements hidden.");
// Get the company name from the page (you can change the selector to match the correct element)
const companyName = document.querySelector('.company-name').innerText.trim();
console.log("Company name found:", companyName);
// Default to 'Contract' if no company name is found
const fileName = companyName ? `${companyName} Contract.pdf` : 'Contract.pdf';
console.log("Generated filename:", fileName);
// Set lower scale for mobile devices to reduce file size
const scale = isMobile ? 1 : 2; // Lower scale on mobile to reduce file size
console.log("Using scale:", scale);
// If mobile, delay the html2canvas capture and image processing by 500ms
const delay = isMobile ? 500 : 0;
setTimeout(function() {
console.log("Starting html2canvas capture...");
// Start html2canvas capture (without options)
html2canvas(content).then(function(canvas) {
console.log("Canvas captured.");
// Determine the image format based on device type (PNG for desktop, JPEG for mobile)
const imgFormat = isMobile ? 'image/jpeg' : 'image/png';
console.log("Using image format:", imgFormat);
// Convert the canvas to a base64 image (JPEG for mobile, PNG for desktop)
setTimeout(function() {
const imgData = canvas.toDataURL(imgFormat); // Switch format based on device type
console.log("Image data created.");
// Get the dimensions of the canvas
const imgWidth = canvas.width;
const imgHeight = canvas.height;
console.log("Canvas dimensions:", imgWidth, imgHeight);
// A4 page dimensions in points
const pageWidth = 595.28;
const pageHeight = 841.89;
// Calculate scaling for A4 page
const scaleX = pageWidth / imgWidth;
const scaleY = pageHeight / imgHeight;
const finalScale = Math.min(scaleX, scaleY);
console.log("Calculated scaling:", finalScale);
// Center the image on the PDF
const xOffset = (pageWidth - imgWidth * finalScale) / 2;
const yOffset = (pageHeight - imgHeight * finalScale) / 2;
console.log("Image positioning: xOffset:", xOffset, "yOffset:", yOffset);
// Delay before adding the image to the PDF (500ms for mobile only)
setTimeout(function() {
doc.addImage(imgData, imgFormat.toUpperCase(), xOffset, yOffset, imgWidth * finalScale, imgHeight * finalScale, undefined, 'FAST');
console.log("Image added to PDF.");
// Delay before saving the PDF (500ms for mobile only)
setTimeout(function() {
// Save the generated PDF with the dynamically created filename
doc.save(fileName);
console.log("PDF saved:", fileName);
// Restore the visibility of the excluded elements
elementsToExclude.forEach(function(el) {
el.style.display = ''; // Restore original display
});
console.log("Excluded elements restored.");
// Ensure the viewport is restored after all steps are complete
if (isMobile) {
const viewportMeta = document.querySelector('meta[name="viewport"]');
if (viewportMeta) {
viewportMeta.setAttribute('content', originalViewportContent);
console.log("Viewport restored to original settings.");
} else {
console.error("Error: Viewport meta tag not found.");
}
}
}, 500); // Delay before saving PDF (500ms for mobile)
}, 500); // Delay before adding image to PDF (500ms)
}, 500); // Delay before converting canvas to image data (500ms)
}).catch(function(error) {
console.error('Error during capture: ', error);
// Restore the visibility of the excluded elements in case of error
elementsToExclude.forEach(function(el) {
el.style.display = ''; // Restore original display
});
// Restore the original viewport settings
if (isMobile) {
const viewportMeta = document.querySelector('meta[name="viewport"]');
if (viewportMeta) {
viewportMeta.setAttribute('content', originalViewportContent);
console.log("Viewport restored to original settings.");
} else {
console.error("Error: Viewport meta tag not found.");
}
}
});
}, delay); // Only apply the delay for mobile
});
</script>