-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
I made several search on how to add the headers of my table, each time a new page is added.
Since there is no concept of "headers" in pdfkit table features, there is no option for that particular behavior
Would be nice to have it, in my opinion
Anyway, since I spent a lot of time adding this feature in my PDF generation, here is a small example on how to do so:
/**
* Pre-calculate the height of a row based on its cell content
*/
function calculateRowHeight(
doc: any,
rowData: any[],
columns: any[],
columnWidths: number[],
rowStyle: any
): number {
let maxHeight = 0;
// Iterate through each cell in the row
rowData.forEach((cellData, colIndex) => {
const column = columns[colIndex];
const colWidth = columnWidths[colIndex];
if (!cellData || !column) return;
const text = String(cellData.text || '');
const fontSize = cellData.fontSize || column.font?.size || 11;
const font = cellData.font || (column.font?.weight === 'bold' ? 'Helvetica-Bold' : 'Helvetica');
// Calculate padding
const padding = typeof cellData.padding === 'number' ? cellData.padding : 4;
const paddingTop = padding;
const paddingBottom = padding;
const paddingLeft = padding;
const paddingRight = padding;
// Available width for text (column width minus padding)
const textWidth = colWidth - paddingLeft - paddingRight;
// Set font for measurement
doc.save();
doc.font(font);
doc.fontSize(fontSize);
// Calculate text height
const textHeight = doc.heightOfString(text, {
width: textWidth,
lineBreak: true,
});
doc.restore();
// Total cell height including padding
const cellHeight = textHeight + paddingTop + paddingBottom;
// Track maximum height
if (cellHeight > maxHeight) {
maxHeight = cellHeight;
}
});
// Apply row height constraints if specified
const minHeight = rowStyle?.minHeight || 0;
const rowHeight = rowStyle?.height;
if (typeof rowHeight === 'number') {
// Fixed height specified
return Math.max(rowHeight, minHeight);
}
// Return calculated height or minimum height, whichever is larger
return Math.max(maxHeight, minHeight);
}
/**
* Check if the next row will trigger a page break
*/
function willNextRowTriggerPageBreak(
doc: any,
nextRowData: any[],
columns: any[],
columnWidths: number[],
rowStyle: any
) {
const currentY = doc.y;
const pageHeight = doc.page.height;
const bottomMargin = doc.page.margins.bottom;
const effectiveBottomLimit = pageHeight - bottomMargin;
// Pre-calculate the next row's height
const nextRowHeight = calculateRowHeight(doc, nextRowData, columns, columnWidths, rowStyle);
if (!nextRowHeight) {
return false; // No height calculated
}
// Check if adding the next row would exceed the page
const nextRowEndY = currentY + nextRowHeight;
return nextRowEndY > (effectiveBottomLimit - 5); // magic number to be sure we don't have edges cases depending on how pdf kit handles this
}
// Combine header and data rows
const tableData = [headerRow, ...dataRows];
let table = doc.table(tableOptions as any);
for (let i = 0; i < tableData.length; i++) {
const rowData = tableData[i];
// Check if the next row will trigger a page break (skip for last row)
if (i < tableData.length - 1) {
const willBreak = willNextRowTriggerPageBreak(
doc,
rowData,
columns,
actualColumnWidths,
element.rowStyle
);
if (willBreak) {
console.log('will break on row', rowData[0].text)
table.end();
doc.addPage();
tableOptions.position.y = doc.page.margins.top;
table = doc.table(tableOptions as any);
table.row(tableData[0] as any);
}
}
table = table.row(rowData as any);
}
monolithed
Metadata
Metadata
Assignees
Labels
No labels