@harbortouch/skytab-analytics-report-utils 0.41.11 → 0.41.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exporters/excel/index.d.cts +2 -2
- package/dist/exporters/excel/index.d.ts +2 -2
- package/dist/exporters/exportBuilder.cjs +4 -1
- package/dist/exporters/exportBuilder.d.cts +1 -1
- package/dist/exporters/exportBuilder.d.ts +1 -1
- package/dist/exporters/exportBuilder.js +4 -1
- package/dist/exporters/pdf/index.cjs +74 -38
- package/dist/exporters/pdf/index.d.cts +2 -1
- package/dist/exporters/pdf/index.d.ts +2 -1
- package/dist/exporters/pdf/index.js +74 -38
- package/dist/{types-JAEAu4KX.d.cts → types-D3IyO__4.d.cts} +1 -0
- package/dist/{types-JAEAu4KX.d.ts → types-D3IyO__4.d.ts} +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ExportSection } from '../../types-
|
|
2
|
-
export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-
|
|
1
|
+
import { a as ExportSection } from '../../types-D3IyO__4.cjs';
|
|
2
|
+
export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-D3IyO__4.cjs';
|
|
3
3
|
|
|
4
4
|
declare class ExcelExporter {
|
|
5
5
|
generate(content: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ExportSection } from '../../types-
|
|
2
|
-
export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-
|
|
1
|
+
import { a as ExportSection } from '../../types-D3IyO__4.js';
|
|
2
|
+
export { E as XlsxFilter, b as XlsxTable, c as XlsxTableColumn } from '../../types-D3IyO__4.js';
|
|
3
3
|
|
|
4
4
|
declare class ExcelExporter {
|
|
5
5
|
generate(content: {
|
|
@@ -4146,7 +4146,10 @@ var ExportBuilder = class {
|
|
|
4146
4146
|
renderTableContent(config, reportData, parameters) {
|
|
4147
4147
|
const data = this.getDataForConfig(reportData, config);
|
|
4148
4148
|
const { columns, headers, columnTypes } = this.resolveColumnsAndHeaders(parameters, config);
|
|
4149
|
-
const tableColumns = columns.map((col, i) =>
|
|
4149
|
+
const tableColumns = columns.map((col, i) => {
|
|
4150
|
+
const size = config.fields[col]?.size;
|
|
4151
|
+
return { header: headers[i], key: col, ...size !== void 0 ? { size } : {} };
|
|
4152
|
+
});
|
|
4150
4153
|
const rows = data.filter((row) => typeof row === "object" && row !== null).map((row) => this.formatRow(row, columns, columnTypes, row));
|
|
4151
4154
|
if (config.hasFooter) {
|
|
4152
4155
|
const totalsRow = this.buildTotalsRow(data, config);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { R as ReportType, A as AnalyticsField } from '../report-Dj8UU5d_.cjs';
|
|
2
|
-
import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-
|
|
2
|
+
import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-D3IyO__4.cjs';
|
|
3
3
|
|
|
4
4
|
declare function resolveRawFiltersToExportFilters(rawFilters: Record<string, (string | number)[] | undefined>, locale: string, reportType?: ReportType): ExportFilter[];
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { R as ReportType, A as AnalyticsField } from '../report-Dj8UU5d_.js';
|
|
2
|
-
import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-
|
|
2
|
+
import { E as ExportFilter, R as ReportMetadata, a as ExportSection } from '../types-D3IyO__4.js';
|
|
3
3
|
|
|
4
4
|
declare function resolveRawFiltersToExportFilters(rawFilters: Record<string, (string | number)[] | undefined>, locale: string, reportType?: ReportType): ExportFilter[];
|
|
5
5
|
|
|
@@ -197,7 +197,10 @@ var ExportBuilder = class {
|
|
|
197
197
|
renderTableContent(config, reportData, parameters) {
|
|
198
198
|
const data = this.getDataForConfig(reportData, config);
|
|
199
199
|
const { columns, headers, columnTypes } = this.resolveColumnsAndHeaders(parameters, config);
|
|
200
|
-
const tableColumns = columns.map((col, i) =>
|
|
200
|
+
const tableColumns = columns.map((col, i) => {
|
|
201
|
+
const size = config.fields[col]?.size;
|
|
202
|
+
return { header: headers[i], key: col, ...size !== void 0 ? { size } : {} };
|
|
203
|
+
});
|
|
201
204
|
const rows = data.filter((row) => typeof row === "object" && row !== null).map((row) => this.formatRow(row, columns, columnTypes, row));
|
|
202
205
|
if (config.hasFooter) {
|
|
203
206
|
const totalsRow = this.buildTotalsRow(data, config);
|
|
@@ -207,7 +207,14 @@ var PdfExporter = class {
|
|
|
207
207
|
const dataFontSize = columnCount > 13 ? 5 : columnCount > 10 ? 6 : columnCount > 7 ? 7 : 8;
|
|
208
208
|
const headerWidthSlack = 2;
|
|
209
209
|
const headerMinWidths = /* @__PURE__ */ new Map();
|
|
210
|
+
const cssPixelsToPoints = 0.75;
|
|
211
|
+
const boundedColumns = /* @__PURE__ */ new Set();
|
|
210
212
|
columns.forEach((col) => {
|
|
213
|
+
if (col.size !== void 0 && Number.isFinite(col.size) && col.size > 0) {
|
|
214
|
+
col.width = col.size * cssPixelsToPoints;
|
|
215
|
+
boundedColumns.add(col);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
211
218
|
doc.font(FONT_BOLD).fontSize(headerFontSize);
|
|
212
219
|
const headerTextWidth = doc.widthOfString(col.header);
|
|
213
220
|
const headerMinWidth = Math.max(...col.header.split(" ").map((w) => doc.widthOfString(w)));
|
|
@@ -226,49 +233,50 @@ var PdfExporter = class {
|
|
|
226
233
|
headerMinWidths.set(col, headerMinWidth + TABLE_CELL_PADDING * 2 + headerWidthSlack);
|
|
227
234
|
});
|
|
228
235
|
const usableWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
|
|
236
|
+
const minimumColumnWidth = Math.min(MIN_COLUMN_WIDTH, usableWidth / columnCount);
|
|
229
237
|
const totalColumnWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
230
238
|
if (totalColumnWidth > usableWidth) {
|
|
231
239
|
const scale = usableWidth / totalColumnWidth;
|
|
232
240
|
columns.forEach((c) => {
|
|
233
|
-
const
|
|
234
|
-
|
|
241
|
+
const width = c.width ?? MIN_COLUMN_WIDTH;
|
|
242
|
+
const headerMin = headerMinWidths.get(c) ?? minimumColumnWidth;
|
|
243
|
+
const minimumWidth = Math.min(width, Math.max(headerMin, minimumColumnWidth));
|
|
244
|
+
c.width = Math.max(Math.floor(width * scale), minimumWidth);
|
|
235
245
|
});
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
const excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
|
|
247
|
+
if (excess > 0) {
|
|
248
|
+
const reducibleWidth = columns.reduce(
|
|
249
|
+
(sum, c) => sum + Math.max((c.width ?? MIN_COLUMN_WIDTH) - minimumColumnWidth, 0),
|
|
250
|
+
0
|
|
251
|
+
);
|
|
252
|
+
if (reducibleWidth > 0) {
|
|
253
|
+
columns.forEach((c) => {
|
|
254
|
+
const width = c.width ?? MIN_COLUMN_WIDTH;
|
|
255
|
+
const available = Math.max(width - minimumColumnWidth, 0);
|
|
256
|
+
c.width = width - excess * (available / reducibleWidth);
|
|
257
|
+
});
|
|
244
258
|
}
|
|
245
259
|
}
|
|
246
260
|
} else if (totalColumnWidth < usableWidth) {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
261
|
+
const expandableColumns = columns.filter((c) => !boundedColumns.has(c));
|
|
262
|
+
const expandableWidth = expandableColumns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
263
|
+
if (expandableWidth > 0) {
|
|
264
|
+
const scale = (expandableWidth + usableWidth - totalColumnWidth) / expandableWidth;
|
|
265
|
+
expandableColumns.forEach((c) => {
|
|
266
|
+
c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
|
|
267
|
+
});
|
|
268
|
+
const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
|
|
269
|
+
const lastExpandableColumn = expandableColumns[expandableColumns.length - 1];
|
|
270
|
+
lastExpandableColumn.width = (lastExpandableColumn.width ?? 0) + (usableWidth - expanded);
|
|
271
|
+
}
|
|
253
272
|
}
|
|
254
273
|
const tableWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
255
274
|
const pageBottom = doc.page.height - doc.page.margins.bottom;
|
|
256
|
-
const calculateRowHeight = (
|
|
257
|
-
|
|
258
|
-
doc.
|
|
259
|
-
let maxLines = 1;
|
|
260
|
-
columns.forEach((col) => {
|
|
261
|
-
const cellValue = isHeader ? col.header : row?.[col.key] !== void 0 ? String(row[col.key]) : "";
|
|
262
|
-
const textWidth = doc.widthOfString(cellValue);
|
|
263
|
-
const availableWidth = (col.width ?? MIN_COLUMN_WIDTH) - TABLE_CELL_PADDING * 2;
|
|
264
|
-
const lines = Math.ceil(textWidth / availableWidth);
|
|
265
|
-
if (lines > maxLines) {
|
|
266
|
-
maxLines = lines;
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
return Math.max(maxLines * (fontSize + 2) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
|
|
275
|
+
const calculateRowHeight = (isHeader = false) => {
|
|
276
|
+
doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(isHeader ? headerFontSize : dataFontSize);
|
|
277
|
+
return Math.max(doc.currentLineHeight(true) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
|
|
270
278
|
};
|
|
271
|
-
const headerHeight = calculateRowHeight(
|
|
279
|
+
const headerHeight = calculateRowHeight(true);
|
|
272
280
|
const drawTableHeader = (y) => this.drawHeader(doc, columns, y, tableWidth, headerHeight, TABLE_CELL_PADDING, headerFontSize, MIN_COLUMN_WIDTH);
|
|
273
281
|
let tableStartY = startY;
|
|
274
282
|
if (tableStartY + headerHeight > pageBottom) {
|
|
@@ -278,7 +286,7 @@ var PdfExporter = class {
|
|
|
278
286
|
let currentY = drawTableHeader(tableStartY);
|
|
279
287
|
doc.font(FONT_REGULAR).fontSize(dataFontSize);
|
|
280
288
|
rows.forEach((row, rowIndex) => {
|
|
281
|
-
const currentRowHeight = calculateRowHeight(
|
|
289
|
+
const currentRowHeight = calculateRowHeight();
|
|
282
290
|
if (currentY + currentRowHeight > pageBottom) {
|
|
283
291
|
doc.addPage();
|
|
284
292
|
currentY = drawTableHeader(doc.page.margins.top);
|
|
@@ -301,6 +309,28 @@ var PdfExporter = class {
|
|
|
301
309
|
doc.strokeColor(HEADER_RULE_COLOR).lineWidth(HEADER_RULE_WIDTH).moveTo(left, closingRuleY).lineTo(left + tableWidth, closingRuleY).stroke();
|
|
302
310
|
return closingRuleY;
|
|
303
311
|
}
|
|
312
|
+
truncateTextToWidth(doc, text, availableWidth) {
|
|
313
|
+
if (doc.widthOfString(text) <= availableWidth) {
|
|
314
|
+
return text;
|
|
315
|
+
}
|
|
316
|
+
const ellipsis = "\u2026";
|
|
317
|
+
if (doc.widthOfString(ellipsis) > availableWidth) {
|
|
318
|
+
return "";
|
|
319
|
+
}
|
|
320
|
+
const characters = Array.from(text);
|
|
321
|
+
let low = 0;
|
|
322
|
+
let high = characters.length;
|
|
323
|
+
while (low < high) {
|
|
324
|
+
const middle = Math.ceil((low + high) / 2);
|
|
325
|
+
const candidate = `${characters.slice(0, middle).join("").trimEnd()}${ellipsis}`;
|
|
326
|
+
if (doc.widthOfString(candidate) <= availableWidth) {
|
|
327
|
+
low = middle;
|
|
328
|
+
} else {
|
|
329
|
+
high = middle - 1;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return `${characters.slice(0, low).join("").trimEnd()}${ellipsis}`;
|
|
333
|
+
}
|
|
304
334
|
drawHeader(doc, columns, startY, tableWidth, headerHeight, cellPadding, headerFontSize, minColumnWidth) {
|
|
305
335
|
const left = doc.page.margins.left;
|
|
306
336
|
doc.rect(left, startY, tableWidth, headerHeight).fill(HEADER_BACKGROUND_COLOR);
|
|
@@ -310,12 +340,15 @@ var PdfExporter = class {
|
|
|
310
340
|
const headerLineHeight = doc.currentLineHeight(true);
|
|
311
341
|
const headerTextY = startY + Math.max((headerHeight - headerLineHeight) / 2, 0);
|
|
312
342
|
columns.forEach((col) => {
|
|
313
|
-
|
|
314
|
-
|
|
343
|
+
const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
|
|
344
|
+
const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
|
|
345
|
+
const headerText = bounded ? this.truncateTextToWidth(doc, col.header, innerWidth) : col.header;
|
|
346
|
+
doc.text(headerText, xPosition + cellPadding, headerTextY, {
|
|
347
|
+
width: innerWidth,
|
|
315
348
|
height: headerLineHeight,
|
|
316
349
|
align: "left",
|
|
317
350
|
lineBreak: false,
|
|
318
|
-
ellipsis:
|
|
351
|
+
ellipsis: !bounded
|
|
319
352
|
});
|
|
320
353
|
xPosition += col.width ?? minColumnWidth;
|
|
321
354
|
});
|
|
@@ -336,12 +369,15 @@ var PdfExporter = class {
|
|
|
336
369
|
const rawValue = row[col.key];
|
|
337
370
|
const cellValue = typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : "";
|
|
338
371
|
const isNumeric = typeof rawValue === "number" || typeof rawValue === "string" && rawValue !== "" && !isNaN(Number(rawValue));
|
|
339
|
-
|
|
340
|
-
|
|
372
|
+
const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
|
|
373
|
+
const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
|
|
374
|
+
const rowText = bounded ? this.truncateTextToWidth(doc, cellValue, innerWidth) : cellValue;
|
|
375
|
+
doc.text(rowText, xPosition + cellPadding, dataTextY, {
|
|
376
|
+
width: innerWidth,
|
|
341
377
|
height: dataLineHeight,
|
|
342
378
|
align: isNumeric ? "right" : "left",
|
|
343
379
|
lineBreak: false,
|
|
344
|
-
ellipsis:
|
|
380
|
+
ellipsis: !bounded
|
|
345
381
|
});
|
|
346
382
|
xPosition += col.width ?? minColumnWidth;
|
|
347
383
|
if (i < columns.length - 1) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-
|
|
1
|
+
import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-D3IyO__4.cjs';
|
|
2
2
|
|
|
3
3
|
type MetaDataValue = ExportFilter[] | string;
|
|
4
4
|
declare class PdfExporter {
|
|
@@ -10,6 +10,7 @@ declare class PdfExporter {
|
|
|
10
10
|
drawSectionTitle(doc: PDFKit.PDFDocument, title: string, startY: number): number;
|
|
11
11
|
drawMetaData(doc: PDFKit.PDFDocument, metaData: Record<string, MetaDataValue>, startY: number): number;
|
|
12
12
|
drawTable(doc: PDFKit.PDFDocument, table: ExportTable, startY: number): number;
|
|
13
|
+
private truncateTextToWidth;
|
|
13
14
|
drawHeader(doc: PDFKit.PDFDocument, columns: ExportTableColumn[], startY: number, tableWidth: number, headerHeight: number, cellPadding: number, headerFontSize: number, minColumnWidth: number): number;
|
|
14
15
|
drawRow(doc: PDFKit.PDFDocument, row: Record<string, unknown>, columns: ExportTableColumn[], currentY: number, rowHeight: number, cellPadding: number, dataFontSize: number, minColumnWidth: number, rowIndex?: number): number;
|
|
15
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-
|
|
1
|
+
import { a as ExportSection, E as ExportFilter, b as ExportTable, c as ExportTableColumn } from '../../types-D3IyO__4.js';
|
|
2
2
|
|
|
3
3
|
type MetaDataValue = ExportFilter[] | string;
|
|
4
4
|
declare class PdfExporter {
|
|
@@ -10,6 +10,7 @@ declare class PdfExporter {
|
|
|
10
10
|
drawSectionTitle(doc: PDFKit.PDFDocument, title: string, startY: number): number;
|
|
11
11
|
drawMetaData(doc: PDFKit.PDFDocument, metaData: Record<string, MetaDataValue>, startY: number): number;
|
|
12
12
|
drawTable(doc: PDFKit.PDFDocument, table: ExportTable, startY: number): number;
|
|
13
|
+
private truncateTextToWidth;
|
|
13
14
|
drawHeader(doc: PDFKit.PDFDocument, columns: ExportTableColumn[], startY: number, tableWidth: number, headerHeight: number, cellPadding: number, headerFontSize: number, minColumnWidth: number): number;
|
|
14
15
|
drawRow(doc: PDFKit.PDFDocument, row: Record<string, unknown>, columns: ExportTableColumn[], currentY: number, rowHeight: number, cellPadding: number, dataFontSize: number, minColumnWidth: number, rowIndex?: number): number;
|
|
15
16
|
}
|
|
@@ -167,7 +167,14 @@ var PdfExporter = class {
|
|
|
167
167
|
const dataFontSize = columnCount > 13 ? 5 : columnCount > 10 ? 6 : columnCount > 7 ? 7 : 8;
|
|
168
168
|
const headerWidthSlack = 2;
|
|
169
169
|
const headerMinWidths = /* @__PURE__ */ new Map();
|
|
170
|
+
const cssPixelsToPoints = 0.75;
|
|
171
|
+
const boundedColumns = /* @__PURE__ */ new Set();
|
|
170
172
|
columns.forEach((col) => {
|
|
173
|
+
if (col.size !== void 0 && Number.isFinite(col.size) && col.size > 0) {
|
|
174
|
+
col.width = col.size * cssPixelsToPoints;
|
|
175
|
+
boundedColumns.add(col);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
171
178
|
doc.font(FONT_BOLD).fontSize(headerFontSize);
|
|
172
179
|
const headerTextWidth = doc.widthOfString(col.header);
|
|
173
180
|
const headerMinWidth = Math.max(...col.header.split(" ").map((w) => doc.widthOfString(w)));
|
|
@@ -186,49 +193,50 @@ var PdfExporter = class {
|
|
|
186
193
|
headerMinWidths.set(col, headerMinWidth + TABLE_CELL_PADDING * 2 + headerWidthSlack);
|
|
187
194
|
});
|
|
188
195
|
const usableWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right;
|
|
196
|
+
const minimumColumnWidth = Math.min(MIN_COLUMN_WIDTH, usableWidth / columnCount);
|
|
189
197
|
const totalColumnWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
190
198
|
if (totalColumnWidth > usableWidth) {
|
|
191
199
|
const scale = usableWidth / totalColumnWidth;
|
|
192
200
|
columns.forEach((c) => {
|
|
193
|
-
const
|
|
194
|
-
|
|
201
|
+
const width = c.width ?? MIN_COLUMN_WIDTH;
|
|
202
|
+
const headerMin = headerMinWidths.get(c) ?? minimumColumnWidth;
|
|
203
|
+
const minimumWidth = Math.min(width, Math.max(headerMin, minimumColumnWidth));
|
|
204
|
+
c.width = Math.max(Math.floor(width * scale), minimumWidth);
|
|
195
205
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
206
|
+
const excess = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0) - usableWidth;
|
|
207
|
+
if (excess > 0) {
|
|
208
|
+
const reducibleWidth = columns.reduce(
|
|
209
|
+
(sum, c) => sum + Math.max((c.width ?? MIN_COLUMN_WIDTH) - minimumColumnWidth, 0),
|
|
210
|
+
0
|
|
211
|
+
);
|
|
212
|
+
if (reducibleWidth > 0) {
|
|
213
|
+
columns.forEach((c) => {
|
|
214
|
+
const width = c.width ?? MIN_COLUMN_WIDTH;
|
|
215
|
+
const available = Math.max(width - minimumColumnWidth, 0);
|
|
216
|
+
c.width = width - excess * (available / reducibleWidth);
|
|
217
|
+
});
|
|
204
218
|
}
|
|
205
219
|
}
|
|
206
220
|
} else if (totalColumnWidth < usableWidth) {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
const expandableColumns = columns.filter((c) => !boundedColumns.has(c));
|
|
222
|
+
const expandableWidth = expandableColumns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
223
|
+
if (expandableWidth > 0) {
|
|
224
|
+
const scale = (expandableWidth + usableWidth - totalColumnWidth) / expandableWidth;
|
|
225
|
+
expandableColumns.forEach((c) => {
|
|
226
|
+
c.width = Math.floor((c.width ?? MIN_COLUMN_WIDTH) * scale);
|
|
227
|
+
});
|
|
228
|
+
const expanded = columns.reduce((sum, c) => sum + (c.width ?? 0), 0);
|
|
229
|
+
const lastExpandableColumn = expandableColumns[expandableColumns.length - 1];
|
|
230
|
+
lastExpandableColumn.width = (lastExpandableColumn.width ?? 0) + (usableWidth - expanded);
|
|
231
|
+
}
|
|
213
232
|
}
|
|
214
233
|
const tableWidth = columns.reduce((sum, c) => sum + (c.width ?? MIN_COLUMN_WIDTH), 0);
|
|
215
234
|
const pageBottom = doc.page.height - doc.page.margins.bottom;
|
|
216
|
-
const calculateRowHeight = (
|
|
217
|
-
|
|
218
|
-
doc.
|
|
219
|
-
let maxLines = 1;
|
|
220
|
-
columns.forEach((col) => {
|
|
221
|
-
const cellValue = isHeader ? col.header : row?.[col.key] !== void 0 ? String(row[col.key]) : "";
|
|
222
|
-
const textWidth = doc.widthOfString(cellValue);
|
|
223
|
-
const availableWidth = (col.width ?? MIN_COLUMN_WIDTH) - TABLE_CELL_PADDING * 2;
|
|
224
|
-
const lines = Math.ceil(textWidth / availableWidth);
|
|
225
|
-
if (lines > maxLines) {
|
|
226
|
-
maxLines = lines;
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
return Math.max(maxLines * (fontSize + 2) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
|
|
235
|
+
const calculateRowHeight = (isHeader = false) => {
|
|
236
|
+
doc.font(isHeader ? FONT_BOLD : FONT_REGULAR).fontSize(isHeader ? headerFontSize : dataFontSize);
|
|
237
|
+
return Math.max(doc.currentLineHeight(true) + TABLE_CELL_PADDING * 2, DEFAULT_ROW_HEIGHT);
|
|
230
238
|
};
|
|
231
|
-
const headerHeight = calculateRowHeight(
|
|
239
|
+
const headerHeight = calculateRowHeight(true);
|
|
232
240
|
const drawTableHeader = (y) => this.drawHeader(doc, columns, y, tableWidth, headerHeight, TABLE_CELL_PADDING, headerFontSize, MIN_COLUMN_WIDTH);
|
|
233
241
|
let tableStartY = startY;
|
|
234
242
|
if (tableStartY + headerHeight > pageBottom) {
|
|
@@ -238,7 +246,7 @@ var PdfExporter = class {
|
|
|
238
246
|
let currentY = drawTableHeader(tableStartY);
|
|
239
247
|
doc.font(FONT_REGULAR).fontSize(dataFontSize);
|
|
240
248
|
rows.forEach((row, rowIndex) => {
|
|
241
|
-
const currentRowHeight = calculateRowHeight(
|
|
249
|
+
const currentRowHeight = calculateRowHeight();
|
|
242
250
|
if (currentY + currentRowHeight > pageBottom) {
|
|
243
251
|
doc.addPage();
|
|
244
252
|
currentY = drawTableHeader(doc.page.margins.top);
|
|
@@ -261,6 +269,28 @@ var PdfExporter = class {
|
|
|
261
269
|
doc.strokeColor(HEADER_RULE_COLOR).lineWidth(HEADER_RULE_WIDTH).moveTo(left, closingRuleY).lineTo(left + tableWidth, closingRuleY).stroke();
|
|
262
270
|
return closingRuleY;
|
|
263
271
|
}
|
|
272
|
+
truncateTextToWidth(doc, text, availableWidth) {
|
|
273
|
+
if (doc.widthOfString(text) <= availableWidth) {
|
|
274
|
+
return text;
|
|
275
|
+
}
|
|
276
|
+
const ellipsis = "\u2026";
|
|
277
|
+
if (doc.widthOfString(ellipsis) > availableWidth) {
|
|
278
|
+
return "";
|
|
279
|
+
}
|
|
280
|
+
const characters = Array.from(text);
|
|
281
|
+
let low = 0;
|
|
282
|
+
let high = characters.length;
|
|
283
|
+
while (low < high) {
|
|
284
|
+
const middle = Math.ceil((low + high) / 2);
|
|
285
|
+
const candidate = `${characters.slice(0, middle).join("").trimEnd()}${ellipsis}`;
|
|
286
|
+
if (doc.widthOfString(candidate) <= availableWidth) {
|
|
287
|
+
low = middle;
|
|
288
|
+
} else {
|
|
289
|
+
high = middle - 1;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return `${characters.slice(0, low).join("").trimEnd()}${ellipsis}`;
|
|
293
|
+
}
|
|
264
294
|
drawHeader(doc, columns, startY, tableWidth, headerHeight, cellPadding, headerFontSize, minColumnWidth) {
|
|
265
295
|
const left = doc.page.margins.left;
|
|
266
296
|
doc.rect(left, startY, tableWidth, headerHeight).fill(HEADER_BACKGROUND_COLOR);
|
|
@@ -270,12 +300,15 @@ var PdfExporter = class {
|
|
|
270
300
|
const headerLineHeight = doc.currentLineHeight(true);
|
|
271
301
|
const headerTextY = startY + Math.max((headerHeight - headerLineHeight) / 2, 0);
|
|
272
302
|
columns.forEach((col) => {
|
|
273
|
-
|
|
274
|
-
|
|
303
|
+
const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
|
|
304
|
+
const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
|
|
305
|
+
const headerText = bounded ? this.truncateTextToWidth(doc, col.header, innerWidth) : col.header;
|
|
306
|
+
doc.text(headerText, xPosition + cellPadding, headerTextY, {
|
|
307
|
+
width: innerWidth,
|
|
275
308
|
height: headerLineHeight,
|
|
276
309
|
align: "left",
|
|
277
310
|
lineBreak: false,
|
|
278
|
-
ellipsis:
|
|
311
|
+
ellipsis: !bounded
|
|
279
312
|
});
|
|
280
313
|
xPosition += col.width ?? minColumnWidth;
|
|
281
314
|
});
|
|
@@ -296,12 +329,15 @@ var PdfExporter = class {
|
|
|
296
329
|
const rawValue = row[col.key];
|
|
297
330
|
const cellValue = typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean" ? String(rawValue) : "";
|
|
298
331
|
const isNumeric = typeof rawValue === "number" || typeof rawValue === "string" && rawValue !== "" && !isNaN(Number(rawValue));
|
|
299
|
-
|
|
300
|
-
|
|
332
|
+
const innerWidth = (col.width ?? minColumnWidth) - cellPadding * 2;
|
|
333
|
+
const bounded = col.size !== void 0 && Number.isFinite(col.size) && col.size > 0;
|
|
334
|
+
const rowText = bounded ? this.truncateTextToWidth(doc, cellValue, innerWidth) : cellValue;
|
|
335
|
+
doc.text(rowText, xPosition + cellPadding, dataTextY, {
|
|
336
|
+
width: innerWidth,
|
|
301
337
|
height: dataLineHeight,
|
|
302
338
|
align: isNumeric ? "right" : "left",
|
|
303
339
|
lineBreak: false,
|
|
304
|
-
ellipsis:
|
|
340
|
+
ellipsis: !bounded
|
|
305
341
|
});
|
|
306
342
|
xPosition += col.width ?? minColumnWidth;
|
|
307
343
|
if (i < columns.length - 1) {
|