-
Notifications
You must be signed in to change notification settings - Fork 3
/
pdfkit-tables.js
120 lines (94 loc) · 3.88 KB
/
pdfkit-tables.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
'use strict';
const PDFDocument = require('pdfkit');
class PDFDocumentWithTables extends PDFDocument {
constructor (options) {
super(options);
}
table (table, arg0, arg1, arg2) {
let startX = this.page.margins.left, startY = this.y;
let options = {};
if ((typeof arg0 === 'number') && (typeof arg1 === 'number')) {
startX = arg0;
startY = arg1;
if (typeof arg2 === 'object')
options = arg2;
} else if (typeof arg0 === 'object') {
options = arg0;
}
const columnCount = table.headers.length;
const columnSpacing = options.columnSpacing || 15;
const rowSpacing = options.rowSpacing || 5;
const usableWidth = options.width || (this.page.width - this.page.margins.left - this.page.margins.right);
const prepareHeader = options.prepareHeader || (() => {});
const prepareRow = options.prepareRow || (() => {});
const computeRowHeight = (row) => {
let result = 0;
row.forEach((cell) => {
const cellHeight = this.heightOfString(cell, {
width: columnWidth,
align: 'left'
});
result = Math.max(result, cellHeight);
});
return result + rowSpacing;
};
const columnContainerWidth = usableWidth / columnCount;
const columnWidth = columnContainerWidth - columnSpacing;
const maxY = this.page.height - this.page.margins.bottom;
let rowBottomY = 0;
this.on('pageAdded', () => {
startY = this.page.margins.top;
rowBottomY = 0;
});
// Allow the user to override style for headers
prepareHeader();
// Check to have enough room for header and first rows
if (startY + 3 * computeRowHeight(table.headers) > maxY)
this.addPage();
// Print all headers
table.headers.forEach((header, i) => {
this.text(header, startX + i * columnContainerWidth, startY, {
width: columnWidth,
align: 'left'
});
});
// Refresh the y coordinate of the bottom of the headers row
rowBottomY = Math.max(startY + computeRowHeight(table.headers), rowBottomY);
// Separation line between headers and rows
this.moveTo(startX, rowBottomY - rowSpacing * 0.5)
.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5)
.lineWidth(2)
.stroke();
table.rows.forEach((row, i) => {
const rowHeight = computeRowHeight(row);
// Switch to next page if we cannot go any further because the space is over.
// For safety, consider 3 rows margin instead of just one
if (startY + 3 * rowHeight < maxY)
startY = rowBottomY + rowSpacing;
else
this.addPage();
// Allow the user to override style for rows
prepareRow(row, i);
// Print all cells of the current row
row.forEach((cell, i) => {
this.text(cell, startX + i * columnContainerWidth, startY, {
width: columnWidth,
align: 'left'
});
});
// Refresh the y coordinate of the bottom of this row
rowBottomY = Math.max(startY + rowHeight, rowBottomY);
// Separation line between rows
this.moveTo(startX, rowBottomY - rowSpacing * 0.5)
.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5)
.lineWidth(1)
.opacity(0.7)
.stroke()
.opacity(1); // Reset opacity after drawing the line
});
this.x = startX;
this.moveDown();
return this;
}
}
module.exports = PDFDocumentWithTables;