Giter Site home page Giter Site logo

natancabral / pdfkit-table Goto Github PK

View Code? Open in Web Editor NEW
88.0 4.0 53.0 11.82 MB

Helps to draw informations in simple tables using pdfkit. #server-side. Generate pdf tables with javascript (PDFKIT plugin)

License: MIT License

JavaScript 100.00%
pdf pdfkit pdf-table pdfkit-table server-side nodejs json javascript

pdfkit-table's Introduction



pdfkit-table (Natan Cabral)

pdfkit-table

Generate pdf tables with javascript (PDFKIT plugin)

Helps to draw informations in simple tables using pdfkit. #server-side.

Examples

view pdf example | color pdf | full code example | server example | json example | all

Install

NPM

npm install pdfkit-table

Use

  // requires
  const fs = require("fs");
  const PDFDocument = require("pdfkit-table");

  // init document
  let doc = new PDFDocument({ margin: 30, size: 'A4' });
  // save document
  doc.pipe(fs.createWriteStream("./document.pdf"));
  
  ;(async function createTable(){
    // table
    const table = { 
      title: '',
      headers: [],
      datas: [ /* complex data */ ],
      rows: [ /* or simple data */ ],
    };

    // the magic (async/await)
    await doc.table(table, { /* options */ });
    // -- or --
    // doc.table(table).then(() => { doc.end() }).catch((err) => { })

    // if your run express.js server
    // to show PDF on navigator
    // doc.pipe(res);

    // done!
    doc.end();
  })();

Examples

Server response

server example

  // router - Node + Express.js
  app.get('/create-pdf', async (req, res) => {
    // ...await table code
    // if your run express.js server
    // to show PDF on navigator
    doc.pipe(res);
    // done!
    doc.end();
  });

Example 1 - Simple Array

  ;(async function(){
    // table 
    const table = {
      title: "Title",
      subtitle: "Subtitle",
      headers: [ "Country", "Conversion rate", "Trend" ],
      rows: [
        [ "Switzerland", "12%", "+1.12%" ],
        [ "France", "67%", "-0.98%" ],
        [ "England", "33%", "+4.44%" ],
      ],
    };
    // A4 595.28 x 841.89 (portrait) (about width sizes)
    // width
    await doc.table(table, { 
      width: 300,
    });
    // or columnsSize
    await doc.table(table, { 
      columnsSize: [ 200, 100, 100 ],
    });
    // done!
    doc.end();
  })();

Example 2 - Table

  ;(async function(){
    // table
    const table = {
      title: "Title",
      subtitle: "Subtitle",
      headers: [
        { label: "Name", property: 'name', width: 60, renderer: null },
        { label: "Description", property: 'description', width: 150, renderer: null }, 
        { label: "Price 1", property: 'price1', width: 100, renderer: null }, 
        { label: "Price 2", property: 'price2', width: 100, renderer: null }, 
        { label: "Price 3", property: 'price3', width: 80, renderer: null }, 
        { label: "Price 4", property: 'price4', width: 43, 
          renderer: (value, indexColumn, indexRow, row, rectRow, rectCell) => { return `U$ ${Number(value).toFixed(2)}` } 
        },
      ],
      // complex data
      datas: [
        { 
          name: 'Name 1', 
          description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean mattis ante in laoreet egestas. ', 
          price1: '$1', 
          price3: '$ 3', 
          price2: '$2', 
          price4: '4', 
        },
        { 
          options: { fontSize: 10, separation: true},
          name: 'bold:Name 2', 
          description: 'bold:Lorem ipsum dolor.', 
          price1: 'bold:$1', 
          price3: { 
            label: 'PRICE $3', options: { fontSize: 12 } 
          }, 
          price2: '$2', 
          price4: '4', 
        },
        // {...},
      ],
      // simeple data
      rows: [
        [
          "Apple",
          "Nullam ut facilisis mi. Nunc dignissim ex ac vulputate facilisis.",
          "$ 105,99",
          "$ 105,99",
          "$ 105,99",
          "105.99",
        ],
        // [...],
      ],
    };
    // the magic
    doc.table(table, {
      prepareHeader: () => doc.font("Helvetica-Bold").fontSize(8),
      prepareRow: (row, indexColumn, indexRow, rectRow, rectCell) => {
        doc.font("Helvetica").fontSize(8);
        indexColumn === 0 && doc.addBackground(rectRow, 'blue', 0.15);
      },
    });
    // done!
    doc.end();
  })();

Example 3 - Json

  ;(async function(){
    // renderer function inside json file
    const tableJson = '{ 
      "headers": [
        { "label":"Name", "property":"name", "width":100 },
        { "label":"Age", "property":"age", "width":100 },
        { "label":"Year", "property":"year", "width":100 }
      ],
      "datas": [
        { "name":"bold:Name 1", "age":"Age 1", "year":"Year 1" },
        { "name":"Name 2", "age":"Age 2", "year":"Year 2" },
        { "name":"Name 3", "age":"Age 3", "year":"Year 3",
          "renderer": "function(value, i, irow){ return value + `(${(1+irow)})`; }"
        }
      ],
      "rows": [
        [ "Name 4", "Age 4", "Year 4" ]
      ],
      "options": {
        "width": 300
      }
    }';
    // the magic
    doc.table(tableJson);
    // done!
    doc.end();
  })();

Example 4 - Json file (many tables)

  ;(async function(){
    // json file
    const json = require('./table.json');
    // if json file is array
    Array.isArray(json) ? 
    // any tables - array
    await doc.tables(json) : 
    // one table - string
    await doc.table(json) ;
    // done!
    doc.end();
  })();

Table

  • Array.<object> | JSON
    • headers Array.<object> | Array.[]
      • label String
      • property String
      • width Number
      • align String
      • valign String
      • headerColor String
      • headerOpacity Number
      • headerAlign String
      • columnColor or backgroundColor: String
      • columnOpacity or backgroundOpacity: Number
      • renderer Function function( value, indexColumn, indexRow, row, rectRow, rectCell ) { return value }
    • datas Array.<object>
    • rows Array.[]
    • title String | Object
    • subtitle String | Object

Headers

Properties Type Default Description
label String undefined description
property String undefined id
width Number undefined width of column
align String left alignment
valign String undefined vertical alignment. ex: valign: "center"
headerColor String grey or #BEBEBE color of header
headerOpacity Number 0.5 opacity of header
headerAlign String left only header
columnColor or backgroundColor String undefined color of column
columnOpacity or backgroundOpacity Number undefined opacity of column
renderer Function Function function( value, indexColumn, indexRow, row, rectRow, rectCell ) { return value }

Simple headers example

const table = {
  // simple headers only with ROWS (not DATAS)  
  headers: ['Name', 'Age'],
  // simple content
  rows: [
    ['Jack', '32'], // row 1
    ['Maria', '30'], // row 2
  ]
};

Complex headers example

const table = {
  // complex headers work with ROWS and DATAS  
  headers: [
    { label:"Name", property: 'name', width: 100, renderer: null },
    { label:"Age", property: 'age', width: 100, renderer: (value) => `U$ ${Number(value).toFixed(1)}` },
  ],
  // complex content
  datas: [
    { name: 'bold:Jack', age: 32, },
    // age is object value with style options
    { name: 'Maria', age: { label: 30 , options: { fontSize: 12 }}, },
  ],
  // simple content (works fine!)
  rows: [
    ['Jack', '32'], // row 1
    ['Maria', '30'], // row 2
  ]
};

Options

Properties Type Default Description
title String Object undefined title
subtitle String Object undefined subtitle
width Number undefined width of table
x Number undefined position x (left). To reset x position set "x: null"
y Number undefined position y (top)
divider Object undefined define divider lines
columnsSize Array undefined define sizes
columnSpacing Number 5
padding Number Array 1 or [1, 5]
addPage Boolean false add table on new page
hideHeader Boolean false hide header
minRowHeight Number 0 min row height
prepareHeader Function Function ()
prepareRow Function Function (row, indexColumn, indexRow, rectRow, rectCell) => {}

Options example

const options = {
  // properties
  title: "Title", // { label: 'Title', fontSize: 30, color: 'blue', fontFamily: "./fonts/type.ttf" },
  subtitle: "Subtitle", // { label: 'Subtitle', fontSize: 20, color: 'green', fontFamily: "./fonts/type.ttf" },
  width: 500, // {Number} default: undefined // A4 595.28 x 841.89 (portrait) (about width sizes)
  x: 0, // {Number} default: undefined | To reset x position set "x: null"
  y: 0, // {Number} default: undefined | 
  divider: {
    header: { disabled: false, width: 2, opacity: 1 },
    horizontal: { disabled: false, width: 0.5, opacity: 0.5 },
  },
  padding: 5, // {Number} default: 0
  columnSpacing: 5, // {Number} default: 5
  hideHeader: false, 
  minRowHeight: 0,
  // functions
  prepareHeader: () => doc.font("Helvetica-Bold").fontSize(8), // {Function} 
  prepareRow: (row, indexColumn, indexRow, rectRow, rectCell) => doc.font("Helvetica").fontSize(8), // {Function} 
}

Options Row

  • separation {Booleon}
  • fontSize {Number}
  • fontFamily {String}
datas: [
  // options row
  { name: 'Jack', options: { fontSize: 10, fontFamily: 'Courier-Bold', separation: true } },
]
  • String
    • bold:
      • 'bold:Jack'
    • size{n}:
      • 'size11:Jack'
      • 'size20:Jack'
datas: [
  // bold
  { name: 'bold:Jack' },
  // size{n}
  { name: 'size20:Maria' },
  { name: 'size8:Will' },
  // normal
  { name: 'San' },
]

Options Cell

  • fontSize {Number}
  • fontFamily {String}
datas: [
  // options cell | value is object | label is string
  { name: { label: 'Jack', options: { fontSize: 10, fontFamily: 'Courier-Bold' } },
]

Fonts Family

  • 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
  • striped {Boolean} (corsimcornao)
  • colspan - the colspan attribute defines the number of columns a table cell should span.
  • sample with database
  • margin: marginBottom before, marginTop after

Changelogs

0.1.90

  • Add options minRowHeight
    • Thanks LouiseEH @LouiseEH
  options: {
    minRowHeight: 30, // pixel
  }

0.1.89

  • Fix first line height
    • Thanks José Luis Francisco @JoseLuis21

0.1.88

  • Fix header font family or title object
    • Thanks @RastaGrzywa
let localType = "./font/Montserrat-Regular.ttf";
const table = {
  title: { label: 'Title Object 2', fontSize: 30, color: 'blue', fontFamily: localType },
}

0.1.87

  • Add options hideHeader
    • Thanks Ville @VilleKoo
  options: {
    hideHeader: true,
  }

0.1.86

  • TypeScript (ts) interface (index.ts)
    • Thanks Côte Arthur @CoteArthur

0.1.83

  • Avoid a table title appearing alone
    • Thanks Alexis Arriola @AlexisArriola
  • Problem with long text in cell spreading on several pages
    • Thanks Ed @MeMineToMe

0.1.72

  • Add Divider Lines on options
  options: {
    // divider lines
    divider: {
      header: {disabled: false, width: 0.5, opacity: 0.5},
      horizontal: {disabled: true, width: 0.5, opacity: 0.5},
    },
  }
  • Thanks Luc Swart @lucswart

0.1.70

  • Fix y position.
    • Thanks Nabil Tahmidul Karim @nabiltkarim

0.1.68

  • Added Promise. table is a Promise();
    • Async/Await function
;(async function(){
  // create document
  const doc = new PDFDocument({ margin: 30, });
  // to save on server
  doc.pipe(fs.createWriteStream("./my-table.pdf"));
  // tables
  await doc.table(table, options);
  await doc.table(table, options);
  await doc.table(table, options);
  // done
  doc.end();
})();
  • Added callback.
  ~~doc.table(table, options, callback)~~;

0.1.63

  • Added valign on headers options. (ex: valign:"center")
  • Added headerAlign, alignment only to header.
    headers: [
      {label:"Name", property:"name", valign: "center", headerAlign:"right", headerColor:"#FF0000", headerOpacity:0.5 }
    ]
    • Thanks @DPCLive

0.1.60

  • Add callback on addBackground function, add .save() and .restore() style.
  • Header font color
    • Thanks @dev-fema

0.1.59

  • Add padding

0.1.57

  • Header color and opacity
    headers: [
      {label:"Name", property:"name", headerColor:"#FF0000", headerOpacity:0.5 }
    ]
    • Thanks Albert Taveras @itsalb3rt

0.1.55

  • Align on headers
    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 {Function} - Add background peer line.
    • doc.addBackground( {x, y, width, height}, fillColor, opacity, callback );
  • prepareRow {Function}
    • const options = { prepareRow: (row, indexColumn, indexRow, rectRow, rectCell) => { indexColumn === 0 && doc.addBackground(rectRow, 'red', 0.5) } }

0.1.38

  • tables {Function} - Add many tables.
    • doc.tables([ table0, table1, table2, ... ]);

0.1.37

  • addPage {Boolean} - 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 {String}
    • const table = { title: "", };
    • const options = { title: "", };
  • add subtitle {String}
    • 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'); {Object}
  • Function allTablesToJson
    • import {allTablesToJson} from 'pdfkit-table';
    • const tables = allTablesToJson(); {Array}

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

The MIT License.

Author

Natan Cabral
[email protected]
https://github.com/natancabral/

Thank you

pdfkit-table's People

Contributors

chigozie-gerald avatar natancabral avatar tolfx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pdfkit-table's Issues

Problem Rows

prepareRow with doc.moveUp(50) not working for first row

image

image

Multiple style in datas (or headers)

Hi! I just wanted to know if it's possible to set different two different style to text in a cell.

During my search I found that you can do something like this:

{ name: 'bold:Jack' }

And it actually came bold.
But I wasn't able to do something like this:

Jack Sparrow

My suggestion is to allow to set a String, an Object OR an Array in the property (in this case name) on datas and the result would be a concatenation of the strings styled. For example:

{ name: [
  { text: 'bold:Jack ' },
  { text: 'Sparrow ' },
  { text: 'THE CAPTAIN', options: { fontFamily: 'Times-Italic' } } 
] }

And return something like

Jack Sparrow THE CAPTAIN

This is my solution, but if there is any better way to implement it I let it in your own; or please tell me if this feature is already possible with the function prepareRow or by other means. Thanks.

Vertical text overlap on row

Hi again!

Is there a way to fix this?

I would like to increase the row width, is that possible?

image

This is my table code:

doc.table(OnlyOwnerTable, {
    columnSpacing: 10,
    width: 490,
    columnsSize: [200, 220, 90],
    padding: 20,
    align: "center",
    prepareHeader: () => doc.font("fonts/Roboto-Regular.ttf").fontSize(11), // {Function}
    prepareRow: (row, indexColumn, indexRow, rectRow) => doc.font("fonts/Roboto-Regular.ttf").fontSize(10).fillColor('#292929'), // {Function}
});

any help is very appreciated

Problem with row height when using barcode font in cell

Hi,

I change font for setting a barcode in a cell in a table, and change the font back again afterwards.
When I do this, the row height is not adjusted to fit the barcode string though.
The only workaround I can find, is adding newlines in one of the other cells, and adding the barcodes after the table has been generated, by saving the x and y coordinates for the cell location where the barcodes should be added.

Tables coming as a stack

Hello, thank you for this amazing library. I'm trying to place 4 tables side by side on the same y panel but they keep on appearing one after another. Gave the same y value for all 4 but still coming on top of each other.
Screenshot 2021-11-17 at 1 43 20 AM
r

Background color per column

Hi,
I would like to know if there is a way to add a background color per column and not per line?

Thank you very much

PDF is empty after the first time

Hello again, the links in row works perfectly, thank you so much for that. Now I just have found an issue.
When I run the local server for the first time and then I generate a pdf it works ok, but when I generate the second one, the pdf is empty.

PDF ok:
pdf full

Second PDF empty:
image

headers on new page?

Wow, I really love this. awesomely done!
I was racking my brain on how to be able to create an invoice with a decent table and then stumbled upon this while Googling...

However, I would need the headers of the table on each new page...

I've been fiddling around in this.on('pageAdded', () => {} but I can't seem to get it right as the "styling" (font and color) on the previous page table is then lost...
What I've got now (which feels a bit "clunky" is:

this.on('pageAdded', () => {
      startY = this.page.margins.top;
      rowBottomY = 0;
      // +++ AW TEST
     // Add table header on each page
      table.headers.forEach((header, i) => {
        this.text(header, startX + i * columnContainerWidth, startY, {
          width: columnWidth,
          align: 'left'
        });
      });
      const rowHeight = computeRowHeight(table.headers);
      rowBottomY = Math.max(startY + rowHeight, rowBottomY);
      this.moveTo(startX, rowBottomY - rowSpacing * 0.5)
        .lineTo(startX + usableWidth, rowBottomY - rowSpacing * 0.5)
        .lineWidth(2)
        .stroke();
      startY = rowBottomY + rowSpacing;
      // --- AW TEST
    });

Any suggestions?

Problem with layout and colors when using prepareRow

Several problems occur when using custom style in rows :

  1. When setting a font-size, the first line height is not properly calculated
  2. When setting background-color, the first column text has an opacity set
  3. When adding twice the same table, columns are superimposed

Here is the code to reproduce and the PDF generated is attached :

    const fs = require("fs");
    const PDFDocument = require("pdfkit-table");

    let doc = new PDFDocument({ margin: 30, size: 'A4' });
    doc.pipe(fs.createWriteStream("./document.pdf"));

    const table1 = {
      headers: [ "head1" , "head2" ],
      rows: [
        ['Prop1', 'Value1'],
        ['Prop2', 'Value2'],
        ['Prop3', 'Value3'],
        ['Prop4', 'Value4']
      ]
    };

    const table2 = {
      headers: [
        { label: "head1", property: 'prop' },
        { label: "head2", property: 'value' }
      ],
      datas: [
        {prop: 'Prop1', value: 'Value1'},
        {prop: 'Prop2', value: 'Value2'},
        {prop: 'Prop3', value: 'Value3'},
        {prop: 'Prop4', value: 'Value4'}
      ],
    };

    const tableOptions1 = {
      prepareRow: (row, indexColumn, indexRow, rectRow) => {
        indexRow === 0 && doc.font("Helvetica").fontSize(22);
      }
    };

    const tableOptions2 = {
      prepareRow: (row, indexColumn, indexRow, rectRow) => {
        indexRow === 0 && doc.font("Helvetica").fontSize(22);
        if(indexColumn === 0) {
          doc.fillColor('white');
          doc.addBackground(rectRow, (indexRow % 2 ? 'blue' : 'green'), 0.5); 
        }
      }
    };

    doc.table(table1, tableOptions1);
    doc.table(table2, tableOptions2);
    doc.table(table2, tableOptions2);
    doc.end();

document.pdf

Table does not add new page automatically anymore

I have noticed that the table doesn't create a new page if the content is long. I found an option called addPage but setting this to true throws an error.

ReferenceError: Cannot access 'onFirePageAdded' before initialization

Cannot stylize title

I've got a bit of a trouble to style title of table. I wonder if there's any possibility to do this.
Based on simple example:

let doc = new PDFDocument({ margin: 30, size: 'A5' });
doc.pipe(fs.createWriteStream("./document.pdf"));
doc.font("./app/fonts/Montserrat-Regular.ttf").fontSize(25);

const table = {
  title: "Title",
  subtitle: "Subtitle",
  headers: ["Country", "Conversion rate", "Trend"],
  rows: [
    ["Switzerland", "12%", "+1.12%"],
    ["France", "67%", "-0.98%"],
    ["England", "33%", "+4.44%"],
  ],
};
doc.font("./app/fonts/Montserrat-Regular.ttf").fontSize(25).table( table, { 
  width: 300,
}); 

doc.end();

I don't know why it doesn't work or how it should work. (Note: I've successfully formatted headers and rows with provided font/size)

Problem Text

Hello, I am having a problem in a cell.

My text contains two words, to fit in the width my second word is cut. Can we force the new line without cutting a word?

Sorry, I'm French and this is a translation.

Assumed PDFDocument default import

The PDFDocument constructor import does not explicitly retrieve the default export from the required pdfkit module, causing builds using newer versions of Babel to fail at runtime.

TypeError: Class extends value #<Object> is not a constructor or null
    at eval (index.js:9:37)
    at ./node_modules/pdfkit-table/index.js (home.js:1359:1)
    at __webpack_require__ (app.js:294:33)
    at fn (app.js:550:21)
    at eval (pdf.ts:7:70)
    at ./src/lib/pdf.ts (home.js:51:1)
    at __webpack_require__ (app.js:294:33)
    at fn (app.js:550:21)
    at eval (index.js??clonedRuleSet-41.use[1]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/pages/nav/HomePage.vue?vue&type=script&lang=ts&setup=true:3:66)
    at ./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use[1]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/pages/nav/HomePage.vue?vue&type=script&lang=ts&setup=tru

Rotating text

image

I wanna achieve something like this, is that possible using pdfkit-table ?

Row splits over several lines in the PDF

Hi,

Sometimes the data of a row is not contained to the row itself, but a new page is inserted with the remaining data on a new page that it otherwise blank.
After many attempts I have not been able to determine the pattern so far, as to why or when this happens.
The last three columns in this example is shown at the bottom of the blank page. It seems to be the columns that come after the cell with the tallest content? It might happen when the last row on a page is taller than what is allowed by the margin?

image
image

Thanks,
-Louise

Forcing sizes to Ints make table dividers and backgrounds out of line

Code is littered with forced Ints using the (>> 0) statement. Some positional elements are forced to INTS and some are using float calculations.

The solution here should be to remove the forced INT conversions to something like parseFloat(). Tested this by replacing the (>> 0) conversations, and everything aligns up smoothly

Table with merged cells

I would like to ask if it is possible to generate a table like this.

image

I have a problem, I cant merge cells of table. Any help?

First header label is printed over table title

I'm creating multiples tables with a helper function. The first table works okay, but the following ones have the first header label mixed with the table title.
image

await doc.table(
        { 
            /* headers: [ // Adding Label on headers override hideHeader
                'field',
                'value'
            ], 
            datas: [], //data.datas,
            title: data.title,
            rows: [], */
            title: "Title",
      subtitle: "Subtitle",
      headers: [
        { label: "Name", property: 'name', width: 60, renderer: null },
        { label: "Description", property: 'description', width: 150, renderer: null }, 
        { label: "Price 1", property: 'price1', width: 100, renderer: null }, 
        { label: "Price 2", property: 'price2', width: 100, renderer: null }, 
        { label: "Price 3", property: 'price3', width: 80, renderer: null }, 
        { label: "Price 4", property: 'price4', width: 43, 
          renderer: (value, indexColumn, indexRow, row, rectRow, rectCell) => { return `U$ ${Number(value).toFixed(2)}` } 
        },
      ],
      // complex data
      datas: [
        { 
          name: 'Name 1', 
          description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean mattis ante in laoreet egestas. ', 
          price1: '$1', 
          price3: '$ 3', 
          price2: '$2', 
          price4: '4', 
        },
        { 
          options: { fontSize: 10, separation: true},
          name: 'bold:Name 2', 
          description: 'bold:Lorem ipsum dolor.', 
          price1: 'bold:$1', 
          price3: { 
            label: 'PRICE $3', options: { fontSize: 12 } 
          }, 
          price2: '$2', 
          price4: '4', 
        },
        // {...},
      ],
      // simeple data
      rows: [
        [
          "Apple",
          "Nullam ut facilisis mi. Nunc dignissim ex ac vulputate facilisis.",
          "$ 105,99",
          "$ 105,99",
          "$ 105,99",
          "105.99",
        ],
        // [...],
      ],


        }
    )

If there is no label, it prints undefined

image

await doc.table(
        { 
            headers: [ // Adding Label on headers override hideHeader
                {  property: 'field' },
                {  property: 'value' },
            ], 
            datas: data.datas,
            title: data.title
        }
    )

I'm using node 14.19.3 and pdfkit-table 0.1.99

Dividers

There is any possibility to put vertical dividers in the table? right now i only see horizontal dividers.

Getting typescript compilation error

Hello

When I use any version after 0.8.6, I am getting below error. Please advise.

node_modules/pdfkit-table/index.ts:1:1 - error TS1208: 'index.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.

How do I use this package with pdfkit?

I have this bit of code below to that instantiates pdfkit... but I'd like to combine pdfkit with pdfkit table. Help??

return new Promise(async (resolve, reject) => {
            const doc = new PDFDocument({size: 'A4', margin: 40});
            const tbldoc = new PDFTable({size: doc.page.size, margin: doc.page.margins});
            doc.pipe(fs.createWriteStream('invoice.pdf'))

            this.row1(doc)
            this.row2( tbldoc )

            doc.end();
})

Header vertical alignment is not working

I have 5 columns and I have a header row.
2 of 5 headers expand in 2 rows (the text is wrapped). I would like that the text in the rest of the column headers to be aligned vertically in the center. It does not seem to work though.

Problem with long text in cell spreading on several pages

If a cell contains a long text making the table spreading on several pages, the layout is broken.
The problem can be simply reproduced with the following code :

const fs = require("fs");
const PDFDocument = require("pdfkit-table");

let doc = new PDFDocument({ margin: 30, size: 'A4' });
doc.pipe(fs.createWriteStream("./document.pdf"));

const lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`;
let longtext = "";
for(let i = 0; i < 20; i++) {
  longtext += `${i + 1}. ${lorem}\n`;
}

const table = {
  headers: [ "Name", "Description" ],
  rows: [
    [ "Name 1", longtext ],
    [ 'Name 2', 'Lorem ipsum dolor.' ],
    [ 'Name 3', longtext ],
    [ 'Name 4', 'Lorem ipsum dolor.' ]
  ]
};

doc.table(table);
doc.end();

Formatting headers text color

How can i set the color for the header text?

const tableJson = {
            "headers": [
                { "label": "Name", "property": "name", "width": 100, "headerColor": "#333333", "headerOpacity": 1 },
                { "label": "Age", "property": "age", "width": 100, "headerColor": "#333333", "headerOpacity": 1 },
                { "label": "Year Func", "property": "year", "width": 100, "headerColor": "#333333", "headerOpacity": 1 }
            ],
            "datas": [
                { "name": "Name 1", "age": "Age 1", "year": "Year 1" },
                { "name": "Name 2", "age": "Age 2", "year": "Year 2" },
                { "name": "Name 3", "age": "Age 3", "year": "Year 3" },
                { "name": "Name 4", "age": "Age 4", "year": "Year 4" },
            ],
            "options": {
                "width": 500,
                "x": null,
                "prepareHeader": () => {
                    doc
                        .fillColor("#ffffff")
                        .fontSize(8)
                        .font(avenirHeavy);
                },
                "prepareRow": (row, indexColumn, indexRow, rectRow) => {
                    if (typeof row === 'object' && Array.isArray(row) === false) {
                        if (indexColumn == 0 && (!_.isEqual(rectRow, i) || !i)) {
                            if (indexRow % 2) {
                                doc.addBackground(rectRow, '#f1f1f1', 0.3);
                                i = _.clone(rectRow)
                                doc.fillColor("#444444")
                                    .fontSize(8)
                                    .font(avenirLight)
                            } else {
                                doc.addBackground(rectRow, '#ffffff', 0.3);
                                i = _.clone(rectRow)
                                doc.fillColor("#444444")
                                    .fontSize(8)
                                    .font(avenirLight)
                            }
                        }
                    }
                }
            }
        };
        doc
            .fontSize(8)
            .table(tableJson);

This code will results in this rendered table.

image

But it is not what I'm trying to achieve which is:

  • black header background with white text

Most likely I'm using the prepareHeader in a wrong way.

Links in rows?

First of all, It's amazing what you have done, really helpful! My question is how I would add a link in a row, for example in pdfkit it would be something like this:

doc
  .fillColor('blue')
  .text('Here is a link!', 100, 100)
  .underline(100, 100, 160, 27, { color: '#0000FF' })
  .link(100, 100, 160, 27, 'http://google.com/');

Ability to rotate header text

Looking for a way to rotate header labels as shown in #15 - essentially this issue is a duplicate of already closed issue. Reopening as #15 seems closed due to missing feedback from reporter.

Use case is large table with matrix data with a lot numbers but longer texts as header.

Headers background

Currently the grey background for the headers only works for the current line, if one of the headers has to linewrap, the next lines will be white instead of gray.

headers wrap

Layout Orientation

Since the table width cant go beyond A4, I was trying to change the layout to landscape to send a report with more than usual columns . Do you have the support right now ?

Correct way to import module from TypeScript

I'm trying to use pdfkit-table in a NestJS web server application written in TypeScript. When trying to instantiate a document I get TypeError: pdfkit_table_1.default is not a constructor.

Environment

pdfkit-table: 0.1.95

tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "target": "es2017",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true
  }
}

What I tried

  1. Default export: fails at runtime with "is not a constructor"
import PDFDocument from "pdfkit-table";
...
const doc = new PDFDocument();

compiles to

const pdfkit_table_1 = require("pdfkit-table");
...
const doc = new pdfkit_table_1.default();
  1. Whole module import: same error. This worked to import pdfkit in another part of the same project.
import * as PDFDocument from "pdfkit-table";
const doc = new PDFDocument.default();

The way it worked with pdfkit was

import * as PDFDocument from "pdfkit";
const doc = new PDFDocument();

And I used the type of PDFDocument as typeof PDFDocument.
If I drop the default from PDFDocument.default() it causes a compilation error: This expression is not constructable (more on this later).

  1. Just about every other way

A solution I found while writing this

What's weird about all this is that VSCode intellisense and indeed the TypeScript compiler sometimes flag the import as not a constructor, but it is actually when they don't that the problem comes up at runtime. This gave me the idea that the TypeScript compiler doesn't understand the contents of the module.

So I tried using the import that caused a compilation error from 2. again, this time disabling error checking.

import * as PDFDocument from "pdfkit-table";
//@ts-ignore
const doc = new PDFDocument();

and it works. When compiled it is

const PDFDocument = require("pdfkit-table");
const doc = new PDFDocument();

makes sense.

Conclusion

I'm no TypeScript expert, but I believe something must be messed up with the module's type declarations.
The compiler thinks the module's default export is a constructor, while it is not, and it also thinks the module itself is not a constructor, while it is actually the very constructor you need.

If there was a way to import and use the module without disabling compilation checks that would be sweet.

Avoid a table title appearing alone

Im creating multiple tables with their respective titles, the problem is at the moment to break the page, the title stays on the previous page and the table its on the next pagem ¿How can i avoid this? thank you in advance for your help

title bug

Add images inside the table?

Is there a way to add an image inside the table?

When I try to add it, it is rendered at the top left of the table and the string [object PDFDocument] is on the cell

Tables overwrite previous tables on the same page

I'm generating multiple tables on one page, one after the other. When reaching the end of the page, I expect the next table to move to a new page, instead what happens is it's placed on top of the same page, thereby overwriting the tables that were placed before.
image

I have created a minimal reproducible example recreating this issue

example
const PDFDocument = require("pdfkit-table");
const path = require("path");
const fs = require("fs");

const doc = new PDFDocument({layout: "landscape"});

const tables = [
    {
        title: "One",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Two",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Three",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Four",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Five",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Six",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Seven",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Eight",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Nine",
        headers: ["Hello"],
        rows: [["World"]],
    },
    {
        title: "Ten",
        headers: ["Hello"],
        rows: [["World"]],
    },
];

for (const table of tables) {
    doc.table(table);
}

doc.end()
const file = fs.createWriteStream(path.join(process.cwd(), "out.pdf"), {flags: "w"})
doc.pipe(file)

For now I'm circumventing the issue with the equivalent of this code replaced in the previous snippet

for (const table of tables) {
    if (doc.y > 0.8 * doc.page.height) {
        doc.addPage()
    }
    doc.table(table);
}

Let me know if you find a better solution.

None of the examples run?

I have my project in typescript, don't think it makes much of a difference. I installed the latest, copied and pasted the examples and ran, got a zero byte PDF.

Running Windows 10 on Node v12.18.3

Align text inside cells

Is there a way to align text (left, right, center) within a cell?.

The documentation does not explain whether it is possible to :(

Nested Tables

Is it possible to have nested table or one row in another row like the image below?
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.