voilab / voilab-pdf-table

PdfKit wrapper that helps to draw informations in simple tables
MIT License
52 stars 26 forks source link

It would be cool to find a way to add styling #2

Open joadr opened 7 years ago

joadr commented 7 years ago

In my project I need to add some data in the tables with different styling, reviewing your code I found out that it should be possible by changing this part of the code:

this.text(data, pos.x + padding.left, y, lodash.assign({
  height: row._renderedContent.height,
  width: width
}, column));

that's right here: https://github.com/voilab/voilab-pdf-table/blob/master/voilab-table.js#L95

This way, this will just add text... but... what do you think about replacing that with:

if (lodash.isFunction(data)) {
      data(self.pdf, pos.x + padding.left, y, lodash.assign({
        height: row._renderedContent.height,
        width: width
      }, column);
    } else {
      self.pdf.text(data, pos.x + padding.left, y, lodash.assign({
        height: row._renderedContent.height,
        width: width
      }, column));
}

This way I can put a function with my own styling, or even put images or anything inside the cell like this:

table.addBody([
      {title: 'Inception', description: function (pdf, x, y, options, column) {
        pdf.font('Helvetica-Bold').text('A movie about dreams', x, y, options, column).font('Helvetica')
      }},
      {title: 'Batman', description: '....'},
])

in theory that should work.... what do you think?

tafel commented 7 years ago

For now, you can achieve your goal with something like this. I use this method to draw images, for example:

table.setColumns([
    {
        id: 'code',
        header: 'Code',
        width: 35,
        height: 18,
        valign: 'center',
        cache: false, // so you can draw your image
        renderer: function (tb, data, draw, column, pos) {
            if (draw) { // at first call: false. Then it's true
                if (!data.barcode) {
                    return 'No barcode (' + data.id + ')';
                }
                tb.pdf.image(data.barcode, pos.x, pos.y, {
                    width: column.width,
                    height: column.height
                });
            }
            return ''; // you need to return a string
        }
    }
]);

Basically, the lib makes 2 calls of the renderer. The first time to calculate the content height, the second time to draw it. Here, we set a fixed height and return an empty string first, and then we draw the image at the second call (and still return an empty string).

Should this does the trick for you?

helgetan commented 7 years ago

Hmm can you give an example for that? Can't get it working. Tried this but 'pos' is undefinied:

.addColumns([
        {
          id: 'beschreibung',
          header: 'Beschreibung',
          align: 'left'
        },
        {
          id: 'zeitraum',
          header: 'Zeitraum',
          width: 100,
          cache: false,
          renderer: function (tb, data, draw, column, pos) {
            tb.pdf.font('Helvetica-Bold').text('A movie about dreams', pos.x, pos.y).font('Helvetica');
            return '';
          }
        },
tafel commented 7 years ago

@helgetan the renderer is called twice. The first time, pos has no value, because nothing is being drawn on the page. When draw is true, it means it's time to draw something on the page. At this moment, pos should have a value. Try this:

renderer: function (tb, data, draw, column, pos) {
    if (draw) {
        tb.pdf.font('Helvetica-Bold').text('A movie about dreams', pos.x, pos.y).font('Helvetica');
    }
    return '';
}