pdfkit-table
Advanced tools
Comparing version 0.1.3 to 0.1.5
665
index.js
@@ -1,2 +0,4 @@ | ||
"use strict"; | ||
// jshint esversion: 6 | ||
// "use strict"; | ||
// https://jshint.com/ | ||
@@ -7,16 +9,49 @@ const PDFDocument = require("pdfkit"); | ||
constructor(options) { | ||
super(options); | ||
constructor(option) { | ||
super(option); | ||
} | ||
logg(...args) { | ||
// console.log(args); | ||
} | ||
/** | ||
* addBackground | ||
* @param {Object} rect | ||
* @param {String} fillColor | ||
* @param {Number} fillOpacity | ||
*/ | ||
addBackground ({x, y, width, height}, fillColor, fillOpacity) { | ||
// validate | ||
fillColor || (fillColor = 'gray'); | ||
fillOpacity || (fillOpacity = 0.1); | ||
// draw bg | ||
this | ||
.fill(fillColor) | ||
//.stroke(fillColor) | ||
.fillOpacity(fillOpacity) | ||
.rect( x, y, width, height ) | ||
//.stroke() | ||
.fill(); | ||
// restore | ||
this | ||
.fillColor('black') | ||
.fillOpacity(1) | ||
.fill(); | ||
} | ||
/** | ||
* table | ||
* @param {object} table | ||
* @param {object} options | ||
* @param {Object} table | ||
* @param {Object} options | ||
* @returns | ||
*/ | ||
table(table, options) { | ||
typeof table === 'string' && (table = JSON.parse(table)); | ||
typeof table === 'string' && ( table = JSON.parse(table) ); | ||
table || (table = {}); | ||
@@ -29,33 +64,149 @@ options || (options = {}); | ||
table.options && (options = table.options); | ||
const columnCount = table.headers.length; | ||
const columnSpacing = options.columnSpacing || 5; // 15 | ||
const columnSizes = options.columnSizes || []; | ||
const columnPositions = []; // 0, 10, 20, 30, 100 | ||
const rowSpacing = options.rowSpacing || 3; // 5 | ||
const usableWidth = options.width || this.page.width - this.page.margins.left - this.page.margins.right; | ||
const prepareHeader = options.prepareHeader || (() => this.font("Helvetica-Bold").fontSize(8) ); | ||
const prepareRow = options.prepareRow || (() => this.font("Helvetica").fontSize(8) ); | ||
options.columnsSize || (options.columnsSize = []); | ||
options.addPage || (options.addPage = false); | ||
const title = table.title ? table.title : ( options.title ? options.title : '' ) ; | ||
const subtitle = table.subtitle ? table.subtitle : ( options.subtitle ? options.subtitle : '' ) ; | ||
const columnIsDefined = options.columnsSize.length ? true : false; | ||
const columnSpacing = options.columnSpacing || 3; // 15 | ||
let columnSizes = []; | ||
let columnPositions = []; // 0, 10, 20, 30, 100 | ||
let columnWidth = 0; | ||
const rowDistance = 0.5; | ||
const prepareHeader = options.prepareHeader || (() => this.font("Helvetica-Bold").fontSize(8)); | ||
const prepareRow = options.prepareRow || ((row, indexColumn, indexRow, rectRow) => this.font("Helvetica").fontSize(8)); | ||
const columnContainerWidth = usableWidth / columnCount; | ||
const columnWidth = columnContainerWidth - columnSpacing; | ||
const maxY = this.page.height - this.page.margins.bottom; | ||
const maxY = this.page.height - (this.page.margins.top + this.page.margins.bottom); | ||
const startX = options.x || this.page.margins.left; | ||
let startY = options.y || this.y; | ||
let rowBottomY = 0; | ||
let tableWidth = 0; | ||
let startX = options.x || this.x || this.page.margins.left; | ||
let startY = options.y || this.y; | ||
let rowBottomY = 0; | ||
let tableWidth = 0; | ||
this.on("pageAdded", () => { | ||
// reset position to margins.left | ||
if( options.x === null || options.x === -1 ){ | ||
startX = this.page.margins.left; | ||
} | ||
const createTitle = ( data, size, opacity ) => { | ||
// Title | ||
if(!data) return; | ||
// get height line | ||
// let cellHeight = 0; | ||
// if string | ||
if(typeof data === 'string' ){ | ||
// font size | ||
this.fontSize( size ).opacity( opacity ); | ||
// get height line | ||
// cellHeight = this.heightOfString( data, { | ||
// width: usableWidth, | ||
// align: "left", | ||
// }); | ||
// write | ||
this.text( data, startX, startY ).opacity( 1 ); // moveDown( 0.5 ) | ||
// startY += cellHeight; | ||
startY = this.y + columnSpacing + 2; | ||
// else object | ||
} else if(typeof data === 'object' ){ | ||
// title object | ||
data.label && this.fontSize( data.fontSize || size ).text( data.label, startX, startY ); | ||
} | ||
}; | ||
// add a new page before crate table | ||
options.addPage === true && this.addPage(); | ||
// create title and subtitle | ||
createTitle( title, 12, 1 ); | ||
createTitle( subtitle, 9, 0.7 ); | ||
// add space after title | ||
if( title || subtitle ){ | ||
startY += 3; | ||
} | ||
const onFirePageAdded = () => { | ||
// startX = this.page.margins.left; | ||
startY = this.page.margins.top; | ||
rowBottomY = 0; | ||
}); | ||
addHeader(); | ||
} | ||
// add fire | ||
this.on("pageAdded", onFirePageAdded); | ||
// warning - eval can be harmful | ||
const fEval = (str) => { | ||
let f = null; eval('f = ' + str); return f; | ||
}; | ||
const separationsRow = (x, y, strokeWidth, strokeOpacity) => { | ||
// validate | ||
strokeOpacity || (strokeOpacity = 0.5); | ||
strokeWidth || (strokeWidth = 0.5); | ||
// distance | ||
const d = rowDistance * 1.5; | ||
// margin | ||
const m = options.x || this.page.margins.left; | ||
// draw | ||
this | ||
.moveTo(x, y - d) | ||
.lineTo(x + tableWidth - m, y - d) | ||
.lineWidth(strokeWidth) | ||
.opacity(strokeOpacity) | ||
.stroke() | ||
// Reset opacity after drawing the line | ||
.opacity(1); | ||
}; | ||
const prepareRowOptions = (row) => { | ||
// validate | ||
if( typeof row !== 'object' || !row.hasOwnProperty('options') ) return; | ||
row.options.hasOwnProperty('fontFamily') && this.font(row.options.fontFamily); | ||
row.options.hasOwnProperty('fontSize') && this.fontSize(row.options.fontSize); | ||
row.options.hasOwnProperty('color') && this.fillColor(row.options.color); | ||
} | ||
const {fontFamily, fontSize, color} = row.options; | ||
fontFamily && this.font(fontFamily); | ||
fontSize && this.fontSize(fontSize); | ||
color && this.fillColor(color); | ||
// row.options.hasOwnProperty('fontFamily') && this.font(row.options.fontFamily); | ||
// row.options.hasOwnProperty('fontSize') && this.fontSize(row.options.fontSize); | ||
// row.options.hasOwnProperty('color') && this.fillColor(row.options.color); | ||
}; | ||
const prepareRowBackground = (row, rect) => { | ||
// validate | ||
if(typeof row !== 'object') return; | ||
// options | ||
row.options && (row = row.options); | ||
// add backgroundColor | ||
if(row.hasOwnProperty('backgroundColor')){ | ||
const { backgroundColor, backgroundOpacity } = row; | ||
// add background | ||
this.addBackground(rect, backgroundColor, backgroundOpacity); | ||
} | ||
// add background | ||
if(row.hasOwnProperty('background')){ | ||
const { color, opacity } = row.background; | ||
// add background | ||
this.addBackground(rect, color, opacity); | ||
} | ||
}; | ||
@@ -65,5 +216,5 @@ const computeRowHeight = (row) => { | ||
let result = 0; | ||
// if row is object, content with property and options | ||
if( !Array.isArray(row) && typeof row === 'object' && !row.hasOwnProperty('property') ){ | ||
if(!Array.isArray(row) && typeof row === 'object' && !row.hasOwnProperty('property')){ | ||
const cells = []; | ||
@@ -89,6 +240,7 @@ // get all properties names on header | ||
text = String(text).replace('bold:',''); | ||
// calc | ||
// calc height size of string | ||
const cellHeight = this.heightOfString(text, { | ||
// width: columnWidth, | ||
width: columnSizes[i], | ||
@@ -102,86 +254,217 @@ align: "left", | ||
return result + rowSpacing; | ||
return result + columnSpacing; | ||
}; | ||
// Allow the user to override style for headers | ||
prepareHeader(); | ||
// Calc columns size | ||
const calcColumnsSizes = () => { | ||
// Check to have enough room for header and first rows. default 3 | ||
if (startY + 2 * computeRowHeight(table.headers) > maxY) this.addPage(); | ||
let h = []; // header width | ||
let p = []; // position | ||
let w = 0; // table width | ||
if(table.headers && table.headers.length > 0){ | ||
// 1o - Max size table | ||
w = this.page.width - this.page.margins.right - ( options.x || this.page.margins.left ); | ||
// 2o - Size defined | ||
options.width && ( w = String(options.width).replace(/[^0-9]/g,'') ); | ||
if(typeof table.headers[0] === 'string' ){ | ||
// 1o | ||
table.headers.forEach( el => { | ||
el.width && h.push(el.width); // - columnSpacing | ||
}); | ||
// 2o | ||
if(h.length === 0) { | ||
h = options.columnsSize; | ||
} | ||
// 3o | ||
if(h.length === 0) { | ||
columnWidth = ( w / table.headers.length ); // - columnSpacing // define column width | ||
table.headers.forEach( () => h.push(columnWidth) ); | ||
} | ||
//Print all headers | ||
table.headers.forEach((header, i) => { | ||
const posX = startX + i * columnContainerWidth; | ||
this.text(header, posX, startY, { | ||
width: columnWidth, | ||
align: "left", | ||
}); | ||
columnSizes.push(columnWidth); | ||
columnPositions.push(posX); | ||
}); | ||
// Set columnPositions | ||
h.reduce((prev, curr, indx) => { | ||
p.push(prev >> 0); | ||
return prev + curr; | ||
},( options.x || this.page.margins.left )); | ||
}else{ | ||
// Set columnSizes | ||
h.length && (columnSizes = h); | ||
p.length && (columnPositions = p); | ||
let rowHeight = computeRowHeight(table.headers); | ||
// 3o - Sum last position + lest header width | ||
w = p[p.length-1] + h[h.length-1]; | ||
// Print all headers | ||
let lastPosition = startX; | ||
table.headers.forEach(({label,width}, i) => { | ||
// Set tableWidth | ||
w && ( tableWidth = w ); | ||
// Ajust spacing | ||
// tableWidth = tableWidth - (h.length * columnSpacing); | ||
this.logg('columnSizes', h); | ||
this.logg('columnPositions', p); | ||
} | ||
calcColumnsSizes(); | ||
// Header | ||
const addHeader = () => { | ||
// Allow the user to override style for headers | ||
prepareHeader(); | ||
let rowHeight = computeRowHeight(table.headers); | ||
let lastPosition = startX; // x position head | ||
// Check to have enough room for header and first rows. default 3 | ||
// if (startY + 2 * rowHeight > maxY) this.addPage(); | ||
if(table.headers && table.headers.length > 0) { | ||
if(typeof table.headers[0] === 'string') { | ||
// we have columnSizes[] complete | ||
if(columnIsDefined) { | ||
// // background header | ||
// const rectRow = { | ||
// x: startX, | ||
// y: startY - columnSpacing - (rowDistance * 2), | ||
// width: columnWidth, | ||
// height: rowHeight + columnSpacing, | ||
// }; | ||
// // add background | ||
// this.addBackground(rectRow); | ||
// print headers | ||
table.headers.forEach((header, i) => { | ||
// background header | ||
const rectCell = { | ||
x: columnPositions[i], | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: columnSizes[i], | ||
height: rowHeight + columnSpacing, | ||
}; | ||
// add background | ||
this.addBackground(rectCell); | ||
this.text(header, lastPosition, startY, { | ||
width: columnSizes[i] >> 0, | ||
align: "left", | ||
}); | ||
lastPosition += columnSizes[i] >> 0; | ||
}); | ||
} else { | ||
// // background header | ||
// const rectRow = { | ||
// x: startX, | ||
// y: startY - columnSpacing - (rowDistance * 2), | ||
// width: columnWidth * table.headers.length, | ||
// height: rowHeight + columnSpacing, | ||
// }; | ||
// // add background | ||
// this.addBackground(rectRow); | ||
// print headers | ||
table.headers.forEach( (header, i) => { | ||
// background header | ||
const rectCell = { | ||
x: lastPosition, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: columnSizes[i], | ||
height: rowHeight + columnSpacing, | ||
}; | ||
// add background | ||
this.addBackground(rectCell); | ||
// lastPosition = startX + i * columnWidth; | ||
this.text(header, lastPosition, startY, { | ||
width: columnWidth, | ||
align: "left", | ||
}); | ||
lastPosition += columnSizes[i] >> 0; | ||
}); | ||
} | ||
width = width >> 0; // number | ||
//this.fillColor('red').strokeColor('#777777'); | ||
// background | ||
this.rect(lastPosition, startY - 5, width - 0, rowHeight + 3) | ||
.fillColor('grey') | ||
.fillOpacity(.1) | ||
.strokeColor('black') | ||
.strokeOpacity(1) | ||
.fill() | ||
.stroke(); | ||
}else{ | ||
// restore color | ||
this.fillColor('black') | ||
.fillOpacity(1) | ||
.strokeOpacity(1); | ||
lastPosition = startX; | ||
// write | ||
this.text(label, lastPosition + 0, startY, { | ||
width: width, | ||
align: "left", | ||
}) | ||
columnSizes.push(width); | ||
columnPositions.push(lastPosition); | ||
lastPosition += width; | ||
}); | ||
// Print all headers | ||
table.headers.forEach(( dataHeader, i) => { | ||
if( table.headers.hasOwnProperty('options') ){ | ||
table.headers.options.hasOwnProperty('fontFamily') && this.font(table.headers.options.fontFamily); | ||
table.headers.options.hasOwnProperty('fontSize') && this.fontSize(table.headers.options.fontSize); | ||
let {label, width, renderer} = dataHeader; | ||
// check defination | ||
width = width || columnSizes[i]; | ||
// force number | ||
width = width >> 0; | ||
if(renderer && typeof renderer === 'string') { | ||
table.headers[i].renderer = fEval(renderer); | ||
} | ||
// background header | ||
const rectRow = { | ||
x: lastPosition, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: width, | ||
height: rowHeight + columnSpacing, | ||
}; | ||
// add background | ||
this.addBackground(rectRow); | ||
// write | ||
this.text(label, lastPosition + 0, startY, { | ||
width: width, | ||
align: "left", | ||
}) | ||
lastPosition += width; | ||
}); | ||
// set style | ||
prepareRowOptions(table.headers); | ||
} | ||
} | ||
} | ||
// Refresh the y coordinate of the bottom of the headers row | ||
rowBottomY = Math.max(startY + computeRowHeight(table.headers), rowBottomY); | ||
// update table width | ||
// tableWidth = columnPositions[columnPositions.length-1] + columnSizes[columnSizes.length-1]; | ||
// this.logg('tableWidth',tableWidth); | ||
// this.logg('columnPositions',columnPositions); | ||
// Separation line between headers and rows | ||
separationsRow(startX, rowBottomY); | ||
} | ||
// Refresh the y coordinate of the bottom of the headers row | ||
rowBottomY = Math.max(startY + computeRowHeight(table.headers), rowBottomY); | ||
tableWidth = columnPositions[columnPositions.length-1] + columnSizes[columnSizes.length-1]; | ||
addHeader(); | ||
// Separation line between headers and rows | ||
this.moveTo(startX, rowBottomY - rowSpacing * 0.5) | ||
//.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineTo(tableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineWidth(1) | ||
.stroke(); | ||
// End header | ||
// complex data | ||
// datas ---------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
// data ------------------------------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
table.datas.forEach((row, i) => { | ||
const rowHeight = computeRowHeight(row); | ||
@@ -191,36 +474,63 @@ | ||
// For safety, consider 3 rows margin instead of just one | ||
if (startY + 2 * rowHeight < maxY) startY = rowBottomY + rowSpacing; | ||
else this.addPage(); | ||
// if (startY + 2 * rowHeight < maxY) startY = rowBottomY + columnSpacing + rowDistance; // 0.5 is spacing rows | ||
// else this.addPage(); | ||
if(startY + 2 * rowHeight >= maxY) this.addPage(); | ||
startY = rowBottomY + columnSpacing + rowDistance; // 0.5 is spacing rows | ||
// Allow the user to override style for rows | ||
prepareRow(row, i); | ||
prepareRowOptions(row); | ||
const rectRow = { | ||
x: startX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: tableWidth - startX, | ||
height: rowHeight + columnSpacing, | ||
}; | ||
if( row.hasOwnProperty('options') ){ | ||
if( row.options.hasOwnProperty('separation') ){ | ||
// Separation line between rows | ||
this.moveTo(startX, rowBottomY - rowSpacing * 0.5) | ||
.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineWidth(1) | ||
.opacity(1) | ||
.stroke(); | ||
} | ||
} | ||
// add background row | ||
prepareRowBackground(row, rectRow); | ||
let posX = startX; | ||
// Print all cells of the current row | ||
table.headers.forEach(({property,width,renderer}, index) => { | ||
table.headers.forEach(( dataHeader, index) => { | ||
let {property, width, renderer} = dataHeader; | ||
// check defination | ||
width = width || columnWidth; | ||
const rectCell = { | ||
x: posX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: width, | ||
height: rowHeight + columnSpacing, | ||
} | ||
// allow the user to override style for rows | ||
prepareRowOptions(row); | ||
prepareRow(row, index, i, rectRow); | ||
let text = row[property]; | ||
// let origText = row[property]; | ||
// cell object | ||
if(typeof text === 'object' ){ | ||
text = String(text.label); // get label | ||
// origText = String(text.label); // get label | ||
row[property].hasOwnProperty('options') && prepareRowOptions(row[property]); // set style | ||
// row[property].hasOwnProperty('options') && prepareRowOptions(row[property]); // set style | ||
// options if text cell is object | ||
if( row[property].hasOwnProperty('options') ){ | ||
// set font style | ||
prepareRowOptions(row[property]); | ||
prepareRowBackground(row[property], rectCell); | ||
} | ||
} else { | ||
// style column by header | ||
prepareRowBackground(table.headers[index], rectCell); | ||
} | ||
// bold | ||
if( text.indexOf('bold:') === 0 ){ | ||
if( String(text).indexOf('bold:') === 0 ){ | ||
this.font('Helvetica-Bold'); | ||
@@ -231,3 +541,3 @@ text = text.replace('bold:',''); | ||
// size | ||
if( text.indexOf('size') === 0 ){ | ||
if( String(text).indexOf('size') === 0 ){ | ||
let size = String(text).substr(4,2).replace(':','').replace('+','') >> 0; | ||
@@ -239,3 +549,6 @@ this.fontSize( size < 7 ? 7 : size ); | ||
// renderer column | ||
renderer && (text = renderer(text, index, i, row)) // text-cell, index-column, index-line, row | ||
// renderer && (text = renderer(text, index, i, row, rectRow, rectCell)) // value, index-column, index-row, row nbhmn | ||
if(typeof renderer === 'function'){ | ||
text = renderer(text, index, i, row, rectRow, rectCell); // value, index-column, index-row, row | ||
} | ||
@@ -248,7 +561,5 @@ this.text(text, posX, startY, { | ||
// repare font family | ||
// if( origText.indexOf('bold:') === 0 || origText.indexOf('size') === 0 ){ | ||
prepareRow(row, i); | ||
prepareRowOptions(row); | ||
// } | ||
// set style | ||
prepareRowOptions(row); | ||
prepareRow(row, index, i, rectRow); | ||
@@ -261,21 +572,18 @@ }); | ||
// Separation line between rows | ||
this.moveTo(startX, rowBottomY - rowSpacing * 0.5) | ||
//.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5) | ||
//.lineTo(posX, rowBottomY - rowSpacing * 0.5) | ||
.lineTo(tableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineWidth(.5) | ||
.opacity(.5) | ||
.stroke() | ||
.opacity(1); // Reset opacity after drawing the line | ||
separationsRow(startX, rowBottomY); | ||
// review this code | ||
if( row.hasOwnProperty('options') ){ | ||
if( row.options.hasOwnProperty('separation') ){ | ||
// Separation line between rows | ||
separationsRow(startX, rowBottomY, 1, 1); | ||
} | ||
} | ||
}); | ||
// ------------------------------------------------------------------------------ | ||
// end data --------------------------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
// end datas | ||
// simple data | ||
// rows ---------------------------------------------------- | ||
table.rows.forEach((row, i) => { | ||
// ------------------------------------------------------------------------------ | ||
// rows ------------------------------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
table.rows.forEach((row, i) => { | ||
const rowHeight = computeRowHeight(row); | ||
@@ -285,18 +593,47 @@ | ||
// For safety, consider 3 rows margin instead of just one | ||
if (startY + 2 * rowHeight < maxY) startY = rowBottomY + rowSpacing; | ||
else this.addPage(); | ||
// if (startY + 3 * rowHeight < maxY) startY = rowBottomY + columnSpacing + rowDistance; // 0.5 is spacing rows | ||
// else this.addPage(); | ||
if(startY + 2 * rowHeight >= maxY) this.addPage(); | ||
startY = rowBottomY + columnSpacing + rowDistance; // 0.5 is spacing rows | ||
// Allow the user to override style for rows | ||
prepareRow(row, i); | ||
const rectRow = { | ||
x: columnPositions[0], | ||
// x: startX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: tableWidth - startX, | ||
height: rowHeight + columnSpacing, | ||
} | ||
// add background | ||
// doc.addBackground(rectRow); | ||
let posX = startX; | ||
row.forEach((cell, index) => { | ||
const rectCell = { | ||
// x: columnPositions[index], | ||
x: posX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: columnSizes[index], | ||
height: rowHeight + columnSpacing, | ||
} | ||
prepareRowBackground(table.headers[index], rectCell); | ||
// Allow the user to override style for rows | ||
prepareRow(row, index, i, rectRow); | ||
// renderer column | ||
if( typeof table.headers[index] === 'object' ){ | ||
table.headers[index].renderer && (cell = table.headers[index].renderer(cell, index, i, row)) // text-cell, index-column, index-line, row | ||
if(typeof table.headers[index] === 'object') { | ||
table.headers[index].renderer && (cell = table.headers[index].renderer(cell, index, i, row, rectRow, rectCell)); // text-cell, index-column, index-line, row | ||
} | ||
// const posX = startX + i * columnContainerWidth; | ||
this.text(cell, columnPositions[index], startY, { | ||
width: columnSizes[index], // columnWidth | ||
this.text(cell, posX, startY, { | ||
width: columnSizes[index], | ||
align: "left", | ||
}); | ||
posX += columnSizes[index]; | ||
}); | ||
@@ -308,14 +645,8 @@ | ||
// Separation line between rows | ||
this.moveTo(startX, rowBottomY - rowSpacing * 0.5) | ||
//.lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineTo(tableWidth, rowBottomY - rowSpacing * 0.5) | ||
.lineWidth(.5) | ||
.opacity(.5) | ||
.stroke() | ||
.opacity(1); // Reset opacity after drawing the line | ||
separationsRow(startX, rowBottomY); | ||
}); | ||
// ------------------------------------------------------------------------------ | ||
// rows ------------------------------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
// end rows ---------------------------------------------------- | ||
// update position | ||
this.x = startX; | ||
@@ -325,6 +656,24 @@ this.y = rowBottomY; // position y final; | ||
// add fire | ||
this.off("pageAdded", onFirePageAdded); | ||
return this; | ||
} | ||
/** | ||
* tables | ||
* @param {Object} tables | ||
* @returns | ||
*/ | ||
tables(tables) { | ||
// if tables is Array | ||
Array.isArray(tables) ? | ||
// for each on Array | ||
tables.forEach( table => this.table( table, table.options || {} ) ) : | ||
// else is tables is a unique table object | ||
( typeof tables === 'object' ? this.table( tables, tables.options || {} ) : null ) ; | ||
} | ||
} | ||
module.exports = PDFDocumentWithTables; |
{ | ||
"name": "pdfkit-table", | ||
"version": "0.1.3", | ||
"version": "0.1.5", | ||
"description": "PdfKit Table. Helps to draw informations in simple tables using pdfkit. #server-side. Generate pdf tables with javascript (PDFKIT plugin) ", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"git-push": "git add . && git commit -m 'update' && git push " | ||
}, | ||
@@ -9,0 +10,0 @@ "repository": "git+https://github.com/natancabral/pdfkit-table.git", |
223
README.md
@@ -10,6 +10,7 @@ # pdfkit-table | ||
[view pdf example](https://github.com/natancabral/pdfkit-table/raw/main/example/document.pdf) | | ||
[color pdf](https://github.com/natancabral/pdfkit-table/raw/main/example/document-color.pdf) | | ||
[full code example](https://github.com/natancabral/pdfkit-table/blob/main/example/index-example.js) | | ||
[server example](https://github.com/natancabral/pdfkit-table/blob/main/example/index-server-example.js) | | ||
[json example](https://github.com/natancabral/pdfkit-table/blob/main/example/index-json-example.js) | | ||
[both](https://github.com/natancabral/pdfkit-table/blob/main/example/) | ||
[all](https://github.com/natancabral/pdfkit-table/blob/main/example/) | ||
@@ -36,2 +37,3 @@ <img src="https://github.com/natancabral/pdfkit-table/blob/main/example/pdf-sample.png"/> | ||
const table = { | ||
title: '', | ||
headers: [], | ||
@@ -51,6 +53,8 @@ datas: [/* complex data */], | ||
### Example 1 - Simple Array Table | ||
### Example 1 - Simple Array | ||
```js | ||
// requires | ||
const tableArray = { | ||
const table = { | ||
title: "Title", | ||
subtitle: "Subtitle", | ||
headers: ["Country", "Conversion rate", "Trend"], | ||
@@ -63,3 +67,7 @@ rows: [ | ||
}; | ||
doc.table( tableArray, { width: 300 }); // A4 595.28 x 841.89 (portrait) (about width sizes) | ||
doc.table( table, { | ||
// A4 595.28 x 841.89 (portrait) (about width sizes) | ||
width: 300, | ||
//columnsSize: [ 200, 100, 100 ], | ||
}); | ||
// end code | ||
@@ -74,2 +82,4 @@ ``` | ||
const table = { | ||
title: "Title", | ||
subtitle: "Subtitle", | ||
headers: [ | ||
@@ -136,3 +146,6 @@ { label:"Name", property: 'name', width: 60, renderer: null }, | ||
prepareHeader: () => doc.font("Helvetica-Bold").fontSize(8), | ||
prepareRow: (row, i) => doc.font("Helvetica").fontSize(8), | ||
prepareRow: (row, indexColumn, indexRow, rectRow) => { | ||
doc.font("Helvetica").fontSize(8); | ||
indexColumn === 0 && doc.addBackground(rectRow, 'blue', 0.15); | ||
}, | ||
}); | ||
@@ -144,3 +157,4 @@ ``` | ||
```js | ||
const tableJson = `{ | ||
// renderer function inside json file | ||
const tableJson = '{ | ||
"headers": [ | ||
@@ -154,3 +168,5 @@ { "label":"Name", "property":"name", "width":100 }, | ||
{ "name":"Name 2", "age":"Age 2", "year":"Year 2" }, | ||
{ "name":"Name 3", "age":"Age 3", "year":"Year 3" } | ||
{ "name":"Name 3", "age":"Age 3", "year":"Year 3", | ||
"renderer": "function(value, i, irow){ return value + `(${(1+irow)})`; }" | ||
} | ||
], | ||
@@ -163,3 +179,3 @@ "rows": [ | ||
} | ||
}` | ||
}'; | ||
doc.table( tableJson ); | ||
@@ -202,3 +218,3 @@ ``` | ||
- <code>Array.<object></code> | ||
- <code>Array.<object></code> | <code>JSON</code> | ||
- headers <code>Array.<object></code> | <code>Array.[]</code> | ||
@@ -208,5 +224,7 @@ - label <code>String</code> | ||
- width <code>Number</code> | ||
- renderer <code>Function</code> function(value, indexColumn, indexRow, row) { return value } | ||
- renderer <code>Function</code> function( value, indexColumn, indexRow, row, rectRow, rectCell ) { return value } | ||
- datas <code>Array.<object></code> | ||
- rows <code>Array.[]</code> | ||
- title <code>String</code> | ||
- subtitle <code>String</code> | ||
@@ -250,9 +268,12 @@ Example code: | ||
-----------------------|-----------------------|--------------------|-------------------| | ||
| **title** | <code>String</code> | undefined | title | | ||
| **subtitle** | <code>String</code> | undefined | subtitle | | ||
| **width** | <code>Number</code> | undefined | width of table | | ||
| **x** | <code>Number</code> | undefined / doc.x | position x (left) | | ||
| **y** | <code>Number</code> | undefined / doc.y | position y (top) | | ||
| **columnsSize** | <code>Array</code> | undefined | define sizes | | ||
| **columnSpacing** | <code>Number</code> | 5 | | | ||
| **rowSpacing** | <code>Number</code> | 3 | | | ||
| **prepareHeader** | <code>Function</code> | Function | | | ||
| **prepareRow** | <code>Function</code> | Function | | | ||
| **addPage** | <code>Boolean</code> | false | add table on new page | | ||
| **prepareHeader** | <code>Function</code> | Function | () | | ||
| **prepareRow** | <code>Function</code> | Function | (row, indexColumn, indexRow, rectRow) => {} | | ||
@@ -264,2 +285,4 @@ | ||
// properties | ||
title: "Title", | ||
subtitle: "Subtitle", | ||
width: 500, // {Number} default: undefined // A4 595.28 x 841.89 (portrait) (about width sizes) | ||
@@ -269,6 +292,5 @@ x: 0, // {Number} default: undefined | doc.x | ||
columnSpacing: 5, // {Number} default: 5 | ||
rowSpacing: 3, // {Number} default: 3 | ||
// functions | ||
prepareHeader: () => doc.font("Helvetica-Bold").fontSize(8), // {Function} | ||
prepareRow: (row, i) => doc.font("Helvetica").fontSize(8), // {Function} | ||
prepareRow: (row, indexColumn, indexRow, rectRow) => doc.font("Helvetica").fontSize(8), // {Function} | ||
} | ||
@@ -279,6 +301,5 @@ ``` | ||
- separation {Booleon} | ||
- fontSize {Number} | ||
- fontFamily {String} | ||
- **bold:|size{n}:** - 'Jack' | 'bold:Jack' | 'size11:Jack' | 'size20:Jack' | ||
- separation <code>{Booleon}</code> | ||
- fontSize <code>{Number}</code> | ||
- fontFamily <code>{String}</code> | ||
@@ -292,2 +313,9 @@ ```js | ||
- String | ||
- **bold:** | ||
- 'bold:Jack' | ||
- **size{n}:** | ||
- 'size11:Jack' | ||
- 'size20:Jack' | ||
```js | ||
@@ -297,2 +325,7 @@ datas: [ | ||
{ name: 'bold:Jack' }, | ||
// size{n} | ||
{ name: 'size20:Maria' }, | ||
{ name: 'size8:Will' }, | ||
// normal | ||
{ name: 'San' }, | ||
] | ||
@@ -303,4 +336,4 @@ ``` | ||
- fontSize {Number} | ||
- fontFamily {String} | ||
- fontSize <code>{Number}</code> | ||
- fontFamily <code>{String}</code> | ||
@@ -316,22 +349,26 @@ ```js | ||
- 'Courier' | ||
- 'Courier-Bold' | ||
- 'Courier-Oblique' | ||
- 'Courier-BoldOblique' | ||
- 'Helvetica' | ||
- 'Helvetica-Bold' | ||
- 'Helvetica-Oblique' | ||
- 'Helvetica-BoldOblique' | ||
- 'Symbol' | ||
- 'Times-Roman' | ||
- 'Times-Bold' | ||
- 'Times-Italic' | ||
- 'Times-BoldItalic' | ||
- 'ZapfDingbats' | ||
- Courier | ||
- Courier-Bold | ||
- Courier-Oblique | ||
- Courier-BoldOblique | ||
- Helvetica | ||
- Helvetica-Bold | ||
- Helvetica-Oblique | ||
- Helvetica-BoldOblique | ||
- Symbol | ||
- Times-Roman | ||
- Times-Bold | ||
- Times-Italic | ||
- Times-BoldItalic | ||
- ZapfDingbats | ||
## ToDo | ||
- [Suggestions / Issues / Fixes](https://github.com/natancabral/pdfkit-table/issues) | ||
- cellPadding {Array} [5,2,5,2]; | ||
- striped {Boolean} (corsimcornao) | ||
- colspan - the colspan attribute defines the number of columns a table cell should span. | ||
- renderer function on cell. Like renderer: (value) => { return `$${value}`} | ||
- load json file - require | string | ||
- sample with database | ||
- alignment | ||
- setFontFamily {String} | ||
@@ -348,5 +385,113 @@ - setBoldFontFamily {String} | ||
- tableLineColor {String} | ||
- backgroundColor {String} | ||
- striped {Boolean} (corsimcornao) | ||
- margin: marginBottom before, marginTop after | ||
- add line bottom or line top | ||
## Changelogs | ||
### 0.1.49 | ||
+ Max size age | ||
### 0.1.48 | ||
+ header height size | ||
+ separate line width | ||
### 0.1.47 | ||
+ addHeader() function on all add pages | ||
- Thanks Anders Wasen ***@QAnders*** | ||
### 0.1.46 | ||
+ addBackground() function to node 8 | ||
- Thanks ***@mehmetunubol*** | ||
### 0.1.45 | ||
+ add **rectCell** on renderer | ||
- renderer = ( value, indexColumn, indexRow, row, rectRow, rectCell ) => {} | ||
- Thanks ***Eduardo Miranda*** | ||
### 0.1.44 | ||
+ Fix paddings and distances | ||
### 0.1.43 | ||
+ Remove **rowSpacing** | ||
+ Fix **columnSpacing** | ||
### 0.1.41 | ||
+ **Background** color on header to colorize ***column*** | ||
- headers: [ | ||
{ label:"Name", property: 'name', ***backgroundColor: 'red', backgroundOpacity: 0.5*** }, | ||
{ label:"Age", property: 'age', ***background: { color: 'green', opacity: 0.5 } }***, | ||
] | ||
+ **Background** color inside row options datas | ||
- datas: [ | ||
{ name:"My Name", age: 20, ***options: { backgroundColor: 'red', backgroundOpacity: 0.5 }*** }, | ||
{ name:"My Name", age: 20, ***options: { background: { color: 'green', opacity: 0.5 } }*** }, | ||
] | ||
+ **Background** color inside cell options datas | ||
- datas: [ | ||
{ name:{ label: "My Name", age: 20, ***options: { backgroundColor: 'red', backgroundOpacity: 0.5 }*** }}, | ||
{ name:{ label: "My Name", age: 20, ***options: { background: { color: 'green', opacity: 0.5 } }*** }}, | ||
] | ||
### 0.1.39 | ||
+ **addBackground** <code>{Function}</code> - Add background peer line. | ||
- doc.addBackground( {x, y, width, height}, fillColor, opacity, fontColor ); | ||
+ **prepareRow** <code>{Function}</code> | ||
- const options = { prepareRow: (row, indexColumn, indexRow, rectRow) => { indexColumn === 0 && doc.addBackground(rectRow, 'red', 0.5) } } | ||
### 0.1.38 | ||
+ **tables** <code>{Function}</code> - Add many tables. | ||
- doc.tables([ table0, table1, table2, ... ]); | ||
### 0.1.37 | ||
+ **addPage** <code>{Boolean}</code> - Add table on new page. | ||
- const options = { addPage: true, }; | ||
### 0.1.36 | ||
+ Fix position x, y of title | ||
+ **options.x**: **null** | **-1** // reset position to margins.left | ||
### 0.1.35 | ||
+ add **title** <code>{String}</code> | ||
- const table = { title: "", }; | ||
- const options = { title: "", }; | ||
+ add **subtitle** <code>{String}</code> | ||
- const table = { subtitle: "", }; | ||
- const options = { subtitle: "", }; | ||
### 0.1.34 | ||
+ add **columnsSize** on options = {} // only to simple table | ||
### 0.1.33 | ||
+ Function **tableToJson** | ||
- import {tableToJson} from 'pdfkit-table'; | ||
- const table = tableToJson('#id_table'); <code>{Object}</code> | ||
+ Function **allTablesToJson** | ||
- import {allTablesToJson} from 'pdfkit-table'; | ||
- const tables = allTablesToJson(); <code>{Array}</code> | ||
### 0.1.32 | ||
+ spacing cell and header alignment | ||
+ **Thank you, contributors!** | ||
### 0.1.31 | ||
+ renderer function on json file. { "renderer": "function(value, icol, irow, row){ return (value+1) + `(${(irow+2)})`; }" } | ||
+ fix width table and separation lines size | ||
## License | ||
@@ -376,2 +521,2 @@ | ||
- ideas - [giuseppe-santoro](https://github.com/foliojs/pdfkit/issues/29#issuecomment-56504943) | ||
- influence [voilab](https://github.com/voilab/voilab-pdf-table) | ||
- influence [voilab](https://github.com/voilab/voilab-pdf-table) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
33383
496
501
2