initial commit
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# PDF Generation — Pagination & Layout
|
||||
|
||||
Applies to: `src/lib/pdf.ts` in spq-v2.
|
||||
|
||||
## Page Break Logic
|
||||
|
||||
The correct page-break pattern for jsPDF 4.x:
|
||||
|
||||
```typescript
|
||||
const CONTENT_BOTTOM = PAGE_H - MARGIN; // 772
|
||||
const FOOTER_HEIGHT = 35; // reserved for footer separator + text + page number
|
||||
|
||||
// Before rendering each service, check if it fits:
|
||||
let svcH = 0;
|
||||
svcH += 5; // decision badge (if present)
|
||||
svcH += 6; // name + price
|
||||
svcH += 16; // priority (if present)
|
||||
svcH += 8; // recommendation (if present)
|
||||
svcH += doc.splitTextToSize(svc.explanation, CW).length * 5 + 2; // explanation
|
||||
svcH += 8; // parts flags (each, if present)
|
||||
svcH += 6; // separator + spacing
|
||||
|
||||
if (y + svcH > CONTENT_BOTTOM - FOOTER_HEIGHT) {
|
||||
y = newPage(doc); // doc.addPage() + y = MARGIN
|
||||
// Redraw section header on new page
|
||||
doc.setFont(...); doc.text(currentSectionLabel, MARGIN, y); y += 8;
|
||||
}
|
||||
```
|
||||
|
||||
**Do NOT use `yPos > PAGE_HEIGHT * 0.7` as a guard** — it blocks breaks in the top 70% of the page, forcing content past the page edge.
|
||||
|
||||
## Footer Rendering
|
||||
|
||||
```typescript
|
||||
function drawFooter(doc, pageNum, totalPages) {
|
||||
doc.setPage(pageNum);
|
||||
const fy = PAGE_H - MARGIN - FOOTER_HEIGHT + 5;
|
||||
doc.line(MARGIN, fy, PAGE_W - MARGIN, fy);
|
||||
doc.text('message', PAGE_W / 2, fy + 15, { align: 'center' });
|
||||
doc.text(`Page ${pageNum} of ${totalPages}`, PAGE_W - MARGIN, PAGE_H - 10, { align: 'right' });
|
||||
}
|
||||
// After all content: loop over pages to draw footer on EVERY page
|
||||
for (let i = 1; i <= doc.getNumberOfPages(); i++) drawFooter(doc, i, totalPages);
|
||||
```
|
||||
|
||||
## Text Rendering (jspdf 4.x)
|
||||
|
||||
Never pass arrays to `doc.text()`. Render `splitTextToSize` results one line at a time:
|
||||
|
||||
```typescript
|
||||
// ❌ Causes overlap in jspdf 4.x:
|
||||
doc.text(lines, MARGIN, yPos);
|
||||
yPos += lines.length * 6;
|
||||
|
||||
// ✅ Correct:
|
||||
lines.forEach((line) => { doc.text(line, MARGIN, yPos); yPos += 6; });
|
||||
```
|
||||
|
||||
## Height Estimator Constants
|
||||
|
||||
The height estimator must match actual yPos increments exactly:
|
||||
|
||||
| Element | yPos Advance |
|
||||
|---------|-------------|
|
||||
| Decision badge | 5 |
|
||||
| Name + price | 6 |
|
||||
| Priority label | 6 |
|
||||
| Priority reason | 10 |
|
||||
| Recommendation | 8 |
|
||||
| Explanation line | 5 |
|
||||
| Explanation gap | 2 |
|
||||
| Parts flag | 8 |
|
||||
| Aftermarket flag | 8 |
|
||||
| Separator + spacing | 6 |
|
||||
Reference in New Issue
Block a user