UNPKG

7.77 kBPlain TextView Raw
1'use strict';
2
3import * as jsPDF from 'jspdf';
4import {Config, FONT_ROW_RATIO, getDefaults} from './config';
5import {addContentHooks, addPage, addTableBorder} from './common';
6import {printRow, printFullRow} from './painter';
7import {calculateWidths} from './calculator';
8import {createModels, validateInput} from './creator';
9
10/**
11 * Create a table from a set of rows and columns.
12 *
13 * @param {Object[]|String[]} headers Either as an array of objects or array of strings
14 * @param {Object[][]|String[][]} data Either as an array of objects or array of strings
15 * @param {Object} [userOptions={}] Options that will override the default ones
16 */
17jsPDF.API.autoTable = function (headers, data, tableOptions = {}) {
18 this.autoTableState = this.autoTableState || {};
19 jsPDF.autoTableState = jsPDF.autoTableState || {};
20
21 let allOptions = [jsPDF.autoTableState.defaults || {}, this.autoTableState.defaults || {}, tableOptions || {}];
22 validateInput(headers, data, allOptions);
23
24 let table = Config.createTable(this);
25 Config.initSettings(table, allOptions);
26 let settings = table.settings;
27
28 // Create the table model with its columns, rows and cells
29 createModels(headers, data);
30 settings.margin = Config.marginOrPadding(settings.margin, getDefaults().margin);
31 calculateWidths(this, Config.pageSize().width);
32
33 table.cursor = {
34 x: table.margin('left'),
35 y: settings.startY === false ? table.margin('top') : settings.startY
36 };
37
38 let minTableBottomPos = settings.startY + table.margin('bottom') + table.headerRow.height;
39 if (settings.pageBreak === 'avoid') {
40 minTableBottomPos += table.height;
41 }
42 let pageHeight = Config.pageSize().height;
43 if ((settings.pageBreak === 'always' && settings.startY !== false) ||
44 (settings.startY !== false && minTableBottomPos > pageHeight)) {
45 table.doc.addPage();
46 table.cursor.y = table.margin('top');
47 }
48 table.pageStartX = table.cursor.x;
49 table.pageStartY = table.cursor.y;
50
51 Config.applyUserStyles();
52 if (settings.showHeader === true || settings.showHeader === 'firstPage' || settings.showHeader === 'everyPage') {
53 printRow(table.headerRow, table.hooks.drawHeaderRow, table.hooks.drawHeaderCell);
54 }
55 Config.applyUserStyles();
56
57 table.rows.forEach(function (row) {
58 printFullRow(row, table.hooks.drawRow, table.hooks.drawCell);
59 });
60
61 addTableBorder();
62
63 // Don't call global and document addPageContent more than once for each page
64 let pageNumber = this.internal.getCurrentPageInfo().pageNumber;
65 if (this.autoTableState.addPageHookPages && this.autoTableState.addPageHookPages[pageNumber]) {
66 if (typeof tableOptions['addPageContent'] === 'function') {
67 tableOptions['addPageContent'](Config.hooksData());
68 }
69 } else {
70 if (!this.autoTableState.addPageHookPages) this.autoTableState.addPageHookPages = {};
71 this.autoTableState.addPageHookPages[pageNumber] = true;
72 addContentHooks();
73 }
74
75 table.finalY = table.cursor.y;
76 this.autoTable.previous = table;
77
78 Config.applyUserStyles();
79
80 return this;
81};
82
83// Enables doc.autoTable.previous.finalY || 40;
84jsPDF.API.autoTable.previous = false;
85
86jsPDF.API.autoTableSetDefaults = function(defaults) {
87 if (!this.autoTableState) this.autoTableState = {};
88
89 if (defaults && typeof defaults === 'object') {
90 this.autoTableState.defaults = defaults;
91 } else {
92 delete this.autoTableState.defaults;
93 }
94
95 return this;
96};
97
98jsPDF.autoTableSetDefaults = function(defaults) {
99 if (!jsPDF.autoTableState) jsPDF.autoTableState = {};
100
101 if (defaults && typeof defaults === 'object') {
102 this.autoTableState.defaults = defaults;
103 } else {
104 delete this.autoTableState.defaults;
105 }
106
107 jsPDF.autoTableState.defaults = defaults;
108};
109
110/**
111 * Parses an html table
112 *
113 * @param tableElem Html table element
114 * @param includeHiddenElements If to include hidden rows and columns (defaults to false)
115 * @returns Object Object with two properties, columns and rows
116 */
117jsPDF.API.autoTableHtmlToJson = function (tableElem, includeHiddenElements) {
118 includeHiddenElements = includeHiddenElements || false;
119
120 if (!tableElem || !(tableElem instanceof HTMLTableElement)) {
121 console.error("A HTMLTableElement has to be sent to autoTableHtmlToJson");
122 return null;
123 }
124
125 let columns = {}, rows = [];
126
127 let header = tableElem.rows[0];
128
129 for (let i = 0; i < header.cells.length; i++) {
130 let cell = header.cells[i];
131 let style = window.getComputedStyle(cell);
132 if (includeHiddenElements || style.display !== 'none') {
133 columns[i] = cell;
134 }
135 }
136
137 for (let i = 1; i < tableElem.rows.length; i++) {
138 let tableRow = tableElem.rows[i];
139 let style = window.getComputedStyle(tableRow);
140 if (includeHiddenElements || style.display !== 'none') {
141 let rowData = [];
142 Object.keys(columns).forEach(function(key) {
143 let cell = tableRow.cells[key];
144 rowData.push(cell);
145 });
146 rows.push(rowData);
147 }
148 }
149
150 let values = Object.keys(columns).map(function(key) { return columns[key] });
151 return {columns: values, rows: rows, data: rows};
152};
153
154/**
155 * Improved text function with halign and valign support
156 * Inspiration from: http://stackoverflow.com/questions/28327510/align-text-right-using-jspdf/28433113#28433113
157 */
158jsPDF.API.autoTableText = function (text, x, y, styles) {
159 if (typeof x !== 'number' || typeof y !== 'number') {
160 console.error('The x and y parameters are required. Missing for the text: ', text);
161 }
162 let k = this.internal.scaleFactor;
163 let fontSize = this.internal.getFontSize() / k;
164
165 let splitRegex = /\r\n|\r|\n/g;
166 let splitText = null;
167 let lineCount = 1;
168 if (styles.valign === 'middle' || styles.valign === 'bottom' || styles.halign === 'center' || styles.halign === 'right') {
169 splitText = typeof text === 'string' ? text.split(splitRegex) : text;
170
171 lineCount = splitText.length || 1;
172 }
173
174 // Align the top
175 y += fontSize * (2 - FONT_ROW_RATIO);
176
177 if (styles.valign === 'middle')
178 y -= (lineCount / 2) * fontSize * FONT_ROW_RATIO;
179 else if (styles.valign === 'bottom')
180 y -= lineCount * fontSize * FONT_ROW_RATIO;
181
182 if (styles.halign === 'center' || styles.halign === 'right') {
183 let alignSize = fontSize;
184 if (styles.halign === 'center')
185 alignSize *= 0.5;
186
187 if (lineCount >= 1) {
188 for (let iLine = 0; iLine < splitText.length; iLine++) {
189 this.text(splitText[iLine], x - this.getStringUnitWidth(splitText[iLine]) * alignSize, y);
190 y += fontSize;
191 }
192 return this;
193 }
194 x -= this.getStringUnitWidth(text) * alignSize;
195 }
196
197 this.text(text, x, y);
198
199 return this;
200};
201
202/**
203 * @deprecated Use doc.autoTable.previous.finalY instead
204 */
205jsPDF.API.autoTableEndPosY = function () {
206 let prev = this.autoTable.previous;
207 if (prev.cursor && typeof prev.cursor.y === 'number') {
208 return prev.cursor.y;
209 } else {
210 return 0;
211 }
212};
213
214/**
215 * @deprecated Use jsPDF.autoTableSetDefaults({addPageContent: function() {}}) instead
216 */
217jsPDF.API.autoTableAddPageContent = function (hook) {
218 if (!jsPDF.API.autoTable.globalDefaults) {
219 jsPDF.API.autoTable.globalDefaults = {};
220 }
221 jsPDF.API.autoTable.globalDefaults.addPageContent = hook;
222 return this;
223};
224
225/**
226 * @deprecated Use data.addPage in hooks instead
227 */
228jsPDF.API.autoTableAddPage = function() {
229 addPage();
230 return this;
231};
\No newline at end of file