UNPKG

jspdf-autotable

Version:

Generate pdf tables with javascript (jsPDF plugin)

234 lines (194 loc) 8.21 kB
import {FONT_ROW_RATIO} from './config'; import {getFillStyle, addTableBorder, applyStyles, applyUserStyles} from './common'; import {Row, Table} from "./models"; import state from "./state"; export function drawTable(table: Table) { let settings = table.settings; table.cursor = { x: table.margin('left'), y: settings.startY == null ? table.margin('top') : settings.startY }; let minTableBottomPos = settings.startY + table.margin('bottom') + table.headHeight + table.footHeight; if (settings.pageBreak === 'avoid') { minTableBottomPos += table.height; } if (settings.pageBreak === 'always' || settings.startY != null && settings.startY !== false && minTableBottomPos > state().pageHeight()) { nextPage(state().doc); table.cursor.y = table.margin('top'); } table.pageStartX = table.cursor.x; table.pageStartY = table.cursor.y; table.startPageNumber = state().pageNumber(); applyUserStyles(); if (settings.showHead === true || settings.showHead === 'firstPage' || settings.showHead === 'everyPage') { table.head.forEach((row) => printRow(row)) } applyUserStyles(); table.body.forEach(function(row, index) { printFullRow(row, index === table.body.length - 1); }); applyUserStyles(); if (settings.showFoot === true || settings.showFoot === 'lastPage' || settings.showFoot === 'everyPage') { table.foot.forEach((row) => printRow(row)) } addTableBorder(); table.callEndPageHooks(); } function printFullRow(row: Row, isLastRow) { let remainingRowHeight = 0; let remainingTexts = {}; let table = state().table; if (!canFitOnPage(row.maxCellHeight, isLastRow)) { if (row.maxCellLineCount <= 1 || (table.settings.rowPageBreak === 'avoid' && !rowHeightGreaterThanMaxTableHeight(row))) { addPage(); } else { // Modify the row to fit the current page and calculate text and height of partial row row.spansMultiplePages = true; let maxCellHeight = 0; let maxRowSpanCellHeight = 0; for (let j = 0; j < table.columns.length; j++) { let column = table.columns[j]; let cell = row.cells[column.dataKey]; if (!cell) { continue; } let fontHeight = cell.styles.fontSize / state().scaleFactor() * FONT_ROW_RATIO; let vPadding = cell.padding('vertical'); let pageHeight = state().pageHeight(); let remainingPageSpace = pageHeight - table.cursor.y - table.margin('bottom'); let remainingLineCount = Math.floor((remainingPageSpace - vPadding) / fontHeight); if (Array.isArray(cell.text) && cell.text.length > remainingLineCount) { let remainingLines = cell.text.splice(remainingLineCount, cell.text.length); remainingTexts[column.dataKey] = remainingLines; let cellHeight = cell.text.length * fontHeight + vPadding; if (cellHeight > maxCellHeight) { maxCellHeight = cellHeight; } let rCellHeight = remainingLines.length * fontHeight + vPadding; if (rCellHeight > remainingRowHeight) { remainingRowHeight = rCellHeight; } } } for (let j = 0; j < table.columns.length; j++) { let column = table.columns[j]; let cell = row.cells[column.dataKey]; cell.height = maxCellHeight; } // Reset row height since text are now removed row.height = maxCellHeight; row.maxCellHeight = maxRowSpanCellHeight; } } printRow(row); // Parts of the row is now printed. Time for adding a new page, prune // the text and start over if (Object.keys(remainingTexts).length > 0) { for (let j = 0; j < table.columns.length; j++) { let col = table.columns[j]; let cell = row.cells[col.dataKey]; cell.height = remainingRowHeight; if (cell) { cell.text = remainingTexts[col.dataKey] || ''; } } addPage(); row.pageNumber++; row.height = remainingRowHeight; printFullRow(row, isLastRow); } } function rowHeightGreaterThanMaxTableHeight(row) { let table = state().table; let pageHeight = state().pageHeight(); let maxTableHeight = pageHeight - table.margin('top') - table.margin('bottom'); return row.maxCellHeight > maxTableHeight } function printRow(row) { let table: Table = state().table; table.cursor.x = table.margin('left'); row.y = table.cursor.y; row.x = table.cursor.x; // For backwards compatibility reset those after addingRow event table.cursor.x = table.margin('left'); row.y = table.cursor.y; row.x = table.cursor.x; for (let column of table.columns) { let cell = row.cells[column.dataKey]; if (!cell) { table.cursor.x += column.width; continue; } applyStyles(cell.styles); cell.x = table.cursor.x; cell.y = row.y; if (cell.styles.valign === 'top') { cell.textPos.y = table.cursor.y + cell.padding('top'); } else if (cell.styles.valign === 'bottom') { cell.textPos.y = table.cursor.y + cell.height - cell.padding('bottom'); } else { cell.textPos.y = table.cursor.y + cell.height / 2; } if (cell.styles.halign === 'right') { cell.textPos.x = cell.x + cell.width - cell.padding('right'); } else if (cell.styles.halign === 'center') { cell.textPos.x = cell.x + cell.width / 2; } else { cell.textPos.x = cell.x + cell.padding('left'); } if (table.callCellHooks(table.cellHooks.willDrawCell, cell, row, column) === false) { table.cursor.x += column.width; continue; } let fillStyle = getFillStyle(cell.styles); if (fillStyle) { state().doc.rect(cell.x, table.cursor.y, cell.width, cell.height, fillStyle); } state().doc.autoTableText(cell.text, cell.textPos.x, cell.textPos.y, { halign: cell.styles.halign, valign: cell.styles.valign, maxWidth: cell.width - cell.padding('left') - cell.padding('right') }); table.callCellHooks(table.cellHooks.didDrawCell, cell, row, column); table.cursor.x += column.width; } table.cursor.y += row.height; } function canFitOnPage(rowHeight, isLastRow) { let table = state().table; let bottomContentHeight = table.margin('bottom'); let showFoot = table.settings.showFoot; if (showFoot === true || showFoot === 'everyPage' || (showFoot === 'lastPage' && isLastRow)) { bottomContentHeight += table.footHeight; } let pos = rowHeight + table.cursor.y + bottomContentHeight; return pos < state().pageHeight(); } export function addPage() { let table: Table = state().table; applyUserStyles(); if (table.settings.showFoot === true || table.settings.showFoot === 'everyPage') { table.foot.forEach((row) => printRow(row)) } table.finalY = table.cursor.y; // Add user content just before adding new page ensure it will // be drawn above other things on the page table.callEndPageHooks(); addTableBorder(); nextPage(state().doc); table.pageNumber++; table.cursor = {x: table.margin('left'), y: table.margin('top')}; table.pageStartX = table.cursor.x; table.pageStartY = table.cursor.y; if (table.settings.showHead === true || table.settings.showHead === 'everyPage') { table.head.forEach((row) => printRow(row)); } } function nextPage(doc) { let current = state().pageNumber(); doc.setPage(current + 1); let newCurrent = state().pageNumber(); if (newCurrent === current) { doc.addPage(); } }