pdfkit-table
Advanced tools
Comparing version 0.1.3 to 0.1.5-5.1
640
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,8 +240,9 @@ // 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], | ||
align: "left", | ||
align: 'left', | ||
}); | ||
@@ -102,86 +254,173 @@ | ||
return result + rowSpacing; | ||
return result + columnSpacing; | ||
}; | ||
// Allow the user to override style for headers | ||
prepareHeader(); | ||
// Calc columns size | ||
const calcColumnSizes = () => { | ||
// 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){ | ||
// (table width) 1o - Max size table | ||
w = this.page.width - this.page.margins.right - ( options.x || this.page.margins.left ); | ||
// (table width) 2o - Size defined | ||
options.width && ( w = String(options.width).replace(/[^0-9]/g,'') >> 0 ); | ||
if(typeof table.headers[0] === 'string' ){ | ||
// (table width) if table is percent of page | ||
// ... | ||
//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); | ||
}); | ||
// (size columns) 1o | ||
table.headers.forEach( el => { | ||
el.width && h.push(el.width); // - columnSpacing | ||
}); | ||
// (size columns) 2o | ||
if(h.length === 0) { | ||
h = options.columnsSize; | ||
} | ||
// (size columns) 3o | ||
if(h.length === 0) { | ||
columnWidth = ( w / table.headers.length ); // - columnSpacing // define column width | ||
table.headers.forEach( () => h.push(columnWidth) ); | ||
} | ||
}else{ | ||
// Set columnPositions | ||
h.reduce((prev, curr, indx) => { | ||
p.push(prev >> 0); | ||
return prev + curr; | ||
},( options.x || this.page.margins.left )); | ||
let rowHeight = computeRowHeight(table.headers); | ||
// !Set columnSizes | ||
h.length && (columnSizes = h); | ||
p.length && (columnPositions = p); | ||
// Print all headers | ||
let lastPosition = startX; | ||
table.headers.forEach(({label,width}, i) => { | ||
// (table width) 3o - Sum last position + lest header width | ||
w = p[p.length-1] + h[h.length-1]; | ||
// !Set tableWidth | ||
w && ( tableWidth = w ); | ||
// Ajust spacing | ||
// tableWidth = tableWidth - (h.length * columnSpacing); | ||
this.logg('columnSizes', h); | ||
this.logg('columnPositions', p); | ||
} | ||
calcColumnSizes(); | ||
// Header | ||
const addHeader = () => { | ||
// Allow the user to override style for headers | ||
prepareHeader(); | ||
let rowHeight = computeRowHeight(table.headers); | ||
let lastPositionX = 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.length > 0) { | ||
// simple header | ||
if(typeof table.headers[0] === 'string') { | ||
// // 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: lastPositionX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: columnSizes[i], | ||
height: rowHeight + columnSpacing, | ||
}; | ||
// add background | ||
this.addBackground(rectCell); | ||
this.text(header, lastPositionX, startY, { | ||
width: columnSizes[i] >> 0, | ||
align: 'left', | ||
}); | ||
lastPositionX += 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); | ||
// Print all headers | ||
table.headers.forEach(( dataHeader, i) => { | ||
// write | ||
this.text(label, lastPosition + 0, startY, { | ||
width: width, | ||
align: "left", | ||
}) | ||
columnSizes.push(width); | ||
columnPositions.push(lastPosition); | ||
lastPosition += width; | ||
}); | ||
let {label, width, renderer, align} = dataHeader; | ||
// check defination | ||
width = width || columnSizes[i]; | ||
align = align || 'left'; | ||
// force number | ||
width = width >> 0; | ||
if(renderer && typeof renderer === 'string') { | ||
table.headers[i].renderer = fEval(renderer); | ||
} | ||
// background header | ||
const rectCell = { | ||
x: lastPositionX, | ||
y: startY - columnSpacing - (rowDistance * 2), | ||
width: width, | ||
height: rowHeight + columnSpacing, | ||
}; | ||
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); | ||
// add background | ||
this.addBackground(rectCell); | ||
// write | ||
this.text(label, lastPositionX, startY, { | ||
width: width, | ||
align: align, | ||
}) | ||
lastPositionX += 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); | ||
// 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]; | ||
// End header | ||
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(); | ||
let lastPositionX; | ||
// complex data | ||
// Datas | ||
table.datas.forEach((row, i) => { | ||
// ------------------------------------------------------------------------------ | ||
// data ------------------------------------------------------------------------- | ||
// ------------------------------------------------------------------------------ | ||
table.datas.forEach((row, i) => { | ||
const rowHeight = computeRowHeight(row); | ||
@@ -191,36 +430,65 @@ | ||
// 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; | ||
lastPositionX = startX; | ||
// Print all cells of the current row | ||
table.headers.forEach(({property,width,renderer}, index) => { | ||
table.headers.forEach(( dataHeader, index) => { | ||
let {property, width, renderer, align} = dataHeader; | ||
// check defination | ||
width = width || columnWidth; | ||
align = align || 'left'; | ||
const rectCell = { | ||
x: lastPositionX, | ||
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 +499,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,15 +507,16 @@ 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 | ||
} | ||
this.text(text, posX, startY, { | ||
this.text(text, lastPositionX, startY, { | ||
width: width, | ||
align: "left", | ||
align: align, | ||
}); | ||
posX += width; | ||
lastPositionX += width; | ||
// 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); | ||
@@ -260,21 +529,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); | ||
@@ -284,18 +550,50 @@ | ||
// 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); | ||
lastPositionX = startX; | ||
row.forEach((cell, index) => { | ||
let align = 'left'; | ||
const rectCell = { | ||
// x: columnPositions[index], | ||
x: lastPositionX, | ||
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 | ||
table.headers[index].align && (align = table.headers[index].align); | ||
} | ||
// const posX = startX + i * columnContainerWidth; | ||
this.text(cell, columnPositions[index], startY, { | ||
width: columnSizes[index], // columnWidth | ||
align: "left", | ||
this.text(cell, lastPositionX, startY, { | ||
width: columnSizes[index], | ||
align: align, | ||
}); | ||
lastPositionX += columnSizes[index]; | ||
}); | ||
@@ -307,14 +605,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; | ||
@@ -324,6 +616,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.55.1", | ||
"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 " | ||
}, | ||
@@ -25,4 +26,4 @@ "repository": "git+https://github.com/natancabral/pdfkit-table.git", | ||
"dependencies": { | ||
"pdfkit": "^0.12.1" | ||
"pdfkit": "latest" | ||
} | ||
} |
260
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,6 +224,28 @@ - label <code>String</code> | ||
- width <code>Number</code> | ||
- renderer <code>Function</code> function(value, indexColumn, indexRow, row) { return value } | ||
- align <code>String</code> | ||
- background <code>Object</code> sample: {"color": "grey", "opacity": 0.5} | ||
- color: <code>String</code> | ||
- opacity: <code>Number</code> | ||
- backgroundColor <code>String</code> 'green' | ||
- backgroundOpacity: <code>Number</code> | ||
- 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> | ||
### Headers | ||
| Properties | Type | Default | Description | | ||
-----------------------|-----------------------|--------------------|-------------------| | ||
| **label** | <code>String</code> | undefined | description | | ||
| **property** | <code>String</code> | undefined | id | | ||
| **width** | <code>Number</code> | undefined | width of column | | ||
| **align** | <code>String</code> | left | alignment | | ||
| **background** | <code>Object</code> | undefined | background of column, sample: {"color": "grey", "opacity": 0.5} | | ||
| **backgroundColor** | <code>String</code> | undefined | color of column | | ||
| **backgroundOpacity**| <code>Number</code> | undefined | opacity of column | | ||
| **renderer** | <code>Function</code> | Function | function( value, indexColumn, indexRow, row, rectRow, rectCell ) { return value } | | ||
Example code: | ||
@@ -250,9 +288,12 @@ ```js | ||
-----------------------|-----------------------|--------------------|-------------------| | ||
| **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 +305,4 @@ | ||
// properties | ||
title: "Title", | ||
subtitle: "Subtitle", | ||
width: 500, // {Number} default: undefined // A4 595.28 x 841.89 (portrait) (about width sizes) | ||
@@ -269,6 +312,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 +321,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 +333,9 @@ ```js | ||
- String | ||
- **bold:** | ||
- 'bold:Jack' | ||
- **size{n}:** | ||
- 'size11:Jack' | ||
- 'size20:Jack' | ||
```js | ||
@@ -297,2 +345,7 @@ datas: [ | ||
{ name: 'bold:Jack' }, | ||
// size{n} | ||
{ name: 'size20:Maria' }, | ||
{ name: 'size8:Will' }, | ||
// normal | ||
{ name: 'San' }, | ||
] | ||
@@ -303,4 +356,4 @@ ``` | ||
- fontSize {Number} | ||
- fontFamily {String} | ||
- fontSize <code>{Number}</code> | ||
- fontFamily <code>{String}</code> | ||
@@ -316,36 +369,147 @@ ```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 | ||
- renderer function on cell. Like renderer: (value) => { return `$${value}`} | ||
- load json file - require | string | ||
- [Suggestions / Issues / Fixes](https://github.com/natancabral/pdfkit-table/issues) | ||
- striped {Boolean} (corsimcornao) | ||
- colspan - the colspan attribute defines the number of columns a table cell should span. | ||
- sample with database | ||
- setFontFamily {String} | ||
- setBoldFontFamily {String} | ||
- alignment | ||
- verticalLines {Boolean} | ||
- verticalLinesWidth {Number} | ||
- verticalLinesColor {String} | ||
- horizontalLines {Boolean} | ||
- horizontalLinesWidth {Number} | ||
- horizontalLinesColor {String} | ||
- tableLine {Boolean} | ||
- tableLineWidth {Number} | ||
- tableLineColor {String} | ||
- backgroundColor {String} | ||
- striped {Boolean} (corsimcornao) | ||
- margin: marginBottom before, marginTop after | ||
## Changelogs | ||
### 0.1.55 | ||
+ align on headers | ||
```json | ||
"headers": [ | ||
{"label":"Name", "property":"name", "align":"center"} | ||
] | ||
``` | ||
- Thanks ***Andrea Fucci*** | ||
### 0.1.49 | ||
+ max size page | ||
### 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 | ||
@@ -375,2 +539,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) |
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
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses eval() which is a dangerous function. This prevents 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
33238
468
520
3
+ Addedjpeg-exif@1.1.4(transitive)
+ Addedpdfkit@0.15.0(transitive)
- Removedpdfkit@0.12.3(transitive)
Updatedpdfkit@latest