1.6 KiB
1.6 KiB
PDF Generation Pagination
Source: src/lib/pdf.ts
Page-break logic
Each service calculates its height before rendering. Page break triggers when y + serviceHeight > CONTENT_BOTTOM - FOOTER_HEIGHT.
Key constants:
CONTENT_BOTTOM = PAGE_H - MARGIN(772)FOOTER_HEIGHT = 35(reserved for separator + footer text + page number)
Height calculation (must match rendering yPos increments)
svcH = 0
if hasDecision: svcH += 5 // badge
svcH += 6 // name + price
if priority: svcH += 16 // priority label + reason
if recommendation: svcH += 8
if explanation: svcH += lines * 5 + 2
if partsNotInStock: svcH += 8 + (deliveryTime ? 8 : 0)
if aftermarket: svcH += 8 + (partsList ? 8 : 0)
svcH += 6 // separator + spacing
After page break
- Call
doc.addPage()then setyPos = MARGIN - Redraw current section header (SERVICES APPROVED / POSTPONED SERVICES) so new page has context
- Summary box uses same FOOTER_HEIGHT check before rendering
Footer
Drawn on EVERY page via post-render loop:
const totalPages = doc.getNumberOfPages();
for (let i = 1; i <= totalPages; i++) {
drawFooter(doc, i, totalPages, settings, shopChargeAmount);
}
Footer includes: separator line, shop message, validity note, "Page N of M"
String rendering (jspdf 4.x)
NEVER pass arrays to doc.text() — jspdf 4.x uses different internal line spacing than manual yPos tracking, causing cascading desync and text overlap. Always render splitTextToSize() results per-line:
doc.splitTextToSize(text, CW).forEach((line) => {
doc.text(line, MARGIN, y);
y += 5;
});