Showing posts with label PDF Creating. Show all posts
Showing posts with label PDF Creating. Show all posts

Thursday, June 16, 2016

jsPDF AutoTable Plugin examples

Bundle.cfg
bundles.Add(new ScriptBundle("~/bundles/jsPDF").Include(
    "~/Scripts/plugins/jsPDF/jspdf.js",
    "~/Scripts/plugins/jsPDF/jspdf.plugin.text-align.js",
    "~/Scripts/plugins/jsPDF/jspdf.plugin.autotable.js"));
jspdf.plugin.text-align.js
(function (api, $) {
    'use strict';
    api.writeText = function (x, y, text, options) {
        options = options || {};
        var defaults = {
            align: 'left',
            width: this.internal.pageSize.width
        }

        var settings = $.extend({}, defaults, options);

        // Get current font size
        var fontSize = this.internal.getFontSize();

        // Get the actual text's width
        /* You multiply the unit width of your string by your font size and divide
         * by the internal scale factor. The division is necessary
         * for the case where you use units other than 'pt' in the constructor
         * of jsPDF.
         */
        var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;

        if (settings.align === 'center')
            x += (settings.width - txtWidth) / 2;
        else if (settings.align === 'right')
            x += (settings.width - txtWidth);

        //default is 'left' alignment
        this.text(text, x, y);
    }
})(jsPDF.API, jQuery);
jsPDF example
/*
 |--------------------------------------------------------------------------
 | This file contains examples of how to use this plugin
 |--------------------------------------------------------------------------
 |
 | To see what the pdfs generated by these examples looks like you can open
 | ´examples.html´ or go to http://simonbengtsson.github.io/jsPDF-AutoTable.
 |
 | To make it possible to view each example in examples.html some extra code
 | are added to the examples below. For example they return their jspdf
 | doc instance and gets generated data from the library faker.js. However you
 | can of course use this plugin how you wish and the simplest first example
 | below would look like this without any extras:
 |
 | var columns = ["ID", "Name", "Age", "City"];
 |
 | var data = [
 |     [1, "Jonatan", 25, "Gothenburg"],
 |     [2, "Simon", 23, "Gothenburg"],
 |     [3, "Hanna", 21, "Stockholm"]
 | ];
 |
 | var doc = new jsPDF('p', 'pt');
 | doc.autoTable(columns, data);
 | doc.save("table.pdf");
 |
 */

var examples = {};

// Default - shows what a default table looks like
examples.auto = function () {
    var doc = new jsPDF('p', 'pt');
    doc.autoTable(getColumns(), getData());
    return doc;
};

// Minimal - shows how compact tables can be drawn
examples.minimal = function () {
    var doc = new jsPDF('p', 'pt');
    doc.autoTable(getColumns(), getData(), {
        tableWidth: 'wrap',
        styles: {cellPadding: 2},
        headerStyles: {rowHeight: 15, fontSize: 8},
        bodyStyles: {rowHeight: 12, fontSize: 8, valign: 'middle'}
    });
    return doc;
};

// Long data - shows how the overflow features looks and can be used
examples.long = function () {
    var doc = new jsPDF('l', 'pt');
    var columnsLong = getColumns().concat([
        {title: shuffleSentence(), dataKey: "text"},
        {title: "Text with a\nlinebreak", dataKey: "text2"}
    ]);

    doc.text("Overflow 'ellipsize' (default)", 10, 40);
    doc.autoTable(columnsLong, getData(), {
        startY: 55,
        margin: {horizontal: 10},
        columnStyles: {text: {columnWidth: 250}}
    });

    doc.text("Overflow 'hidden'", 10, doc.autoTableEndPosY() + 30);
    doc.autoTable(columnsLong, getData(), {
        startY: doc.autoTableEndPosY() + 45,
        margin: {horizontal: 10},
        styles: {overflow: 'hidden'},
        columnStyles: {email: {columnWidth: 160}}
    });

    doc.text("Overflow 'linebreak'", 10, doc.autoTableEndPosY() + 30);
    doc.autoTable(columnsLong, getData(3), {
        startY: doc.autoTableEndPosY() + 45,
        margin: {horizontal: 10},
        styles: {overflow: 'linebreak'},
        bodyStyles: {valign: 'top'},
        columnStyles: {email: {columnWidth: 'wrap'}},
    });

    return doc;
};

// Content - shows how tables can be integrated with any other pdf content
examples.content = function () {
    var doc = new jsPDF('p', 'pt');

    doc.setFontSize(18);
    doc.text('A story about Miusov', 40, 60);
    doc.setFontSize(11);
    doc.setTextColor(100);
    var text = doc.splitTextToSize(shuffleSentence(faker.lorem.words(55)) + '.', doc.internal.pageSize.width - 80, {});
    doc.text(text, 40, 80);

    var cols = getColumns();
    cols.splice(0, 2);
    doc.autoTable(cols, getData(40), {startY: 150});

    doc.text(text, 40, doc.autoTableEndPosY() + 30);

    return doc;
};

// Multiple - shows how multiple tables can be drawn both horizontally and vertically
examples.multiple = function () {
    var doc = new jsPDF('p', 'pt');
    doc.setFontSize(22);
    doc.text("Multiple tables", 40, 60);
    doc.setFontSize(12);

    doc.autoTable(getColumns().slice(0, 3), getData(), {
        startY: 90,
        pageBreak: 'avoid',
        margin: {right: 305}
    });

    doc.autoTable(getColumns().slice(0, 3), getData(), {
        startY: 90,
        pageBreak: 'avoid',
        margin: {left: 305}
    });

    for (var j = 0; j < 6; j++) {
        doc.autoTable(getColumns(), getData(9), {
            startY: doc.autoTableEndPosY() + 30,
            pageBreak: 'avoid',
        });
    }

    return doc;
};

// From html - shows how pdf tables can be be drawn from html tables
examples.html = function () {
    var doc = new jsPDF('p', 'pt');
    doc.text("From HTML", 40, 50);
    var res = doc.autoTableHtmlToJson(document.getElementById("basic-table"));
    doc.autoTable(res.columns, res.data, {startY: 60});
    return doc;
};

// Header and footers - shows how header and footers can be drawn
examples['header-footer'] = function () {
    var doc = new jsPDF('p', 'pt');

    var header = function (data) {
        doc.setFontSize(20);
        doc.setTextColor(40);
        doc.setFontStyle('normal');
        doc.addImage(headerImgData, 'JPEG', data.settings.margin.left, 40, 25, 25);
        doc.text("Report", data.settings.margin.left + 35, 60);
    };

    var totalPagesExp = "{total_pages_count_string}";
    var footer = function (data) {
        var str = "Page " + data.pageCount;
        // Total page number plugin only available in jspdf v1.0+
        if (typeof doc.putTotalPages === 'function') {
            str = str + " of " + totalPagesExp;
        }
        doc.text(str, data.settings.margin.left, doc.internal.pageSize.height - 30);
    };

    var options = {
        beforePageContent: header,
        afterPageContent: footer,
        margin: {top: 80}
    };
    doc.autoTable(getColumns(), getData(40), options);

    // Total page number plugin only available in jspdf v1.0+
    if (typeof doc.putTotalPages === 'function') {
        doc.putTotalPages(totalPagesExp);
    }

    return doc;
};

// Themes - shows how the different themes looks
examples.themes = function () {
    var doc = new jsPDF('p', 'pt');
    doc.setFontSize(12);
    doc.setFontStyle('bold');

    doc.text('Theme "striped"', 40, 50);
    doc.autoTable(getColumns(), getData(), {startY: 60});

    doc.text('Theme "grid"', 40, doc.autoTableEndPosY() + 30);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTableEndPosY() + 40, theme: 'grid'});

    doc.text('Theme "plain"', 40, doc.autoTableEndPosY() + 30);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTableEndPosY() + 40, theme: 'plain'});

    return doc;
};

// Horizontal - shows how tables can be drawn with horizontal headers
examples.horizontal = function () {
    var doc = new jsPDF('p', 'pt');
    doc.autoTable(getColumns().splice(1,4), getData(), {
        drawHeaderRow: function() {
            // Don't draw header row
            return false;
        },
        columnStyles: {
            first_name: {fillColor: [41, 128, 185], textColor: 255, fontStyle: 'bold'}
        }
    });
    return doc;
};


// Custom style - shows how custom styles can be applied to tables
examples.custom = function () {
    var doc = new jsPDF('p', 'pt');
    doc.autoTable(getColumns().slice(2, 6), getData(20), {
        styles: {
            font: 'courier',
            fillStyle: 'DF',
            lineColor: [44, 62, 80],
            lineWidth: 2
        },
        headerStyles: {
            fillColor: [44, 62, 80],
            fontSize: 15,
            rowHeight: 30
        },
        bodyStyles: {
            fillColor: [52, 73, 94],
            textColor: 240
        },
        alternateRowStyles: {
            fillColor: [74, 96, 117]
        },
        columnStyles: {
            email: {
                fontStyle: 'bold'
            }
        },
        createdCell: function (cell, data) {
            if (data.column.dataKey === 'expenses') {
                cell.styles.halign = 'right';
                if (cell.raw > 600) {
                    cell.styles.textColor = [255, 100, 100];
                    cell.styles.fontStyle = 'bolditalic';
                }
                cell.text = '$' + cell.text;
            } else if (data.column.dataKey === 'country') {
                cell.text = cell.raw.split(' ')[0];
            }
        }
    });
    return doc;
};

// Custom style - shows how custom styles can be applied to tables
examples.spans = function () {
    var doc = new jsPDF('p', 'pt');
    doc.setFontSize(12);
    doc.setTextColor(0);
    doc.setFontStyle('bold');
    doc.text('Col and row span', 40, 50);
    var data = getData(20);
    data.sort(function (a, b) {
        return parseFloat(b.expenses) - parseFloat(a.expenses);
    });
    doc.autoTable(getColumns(), data, {
        theme: 'grid',
        startY: 60,
        drawRow: function (row, data) {
            // Colspan
            doc.setFontStyle('bold');
            doc.setFontSize(10);
            if (row.index === 0) {
                doc.setTextColor(200, 0, 0);
                doc.rect(data.settings.margin.left, row.y, data.table.width, 20, 'S');
                doc.autoTableText("Priority Group", data.settings.margin.left + data.table.width / 2, row.y + row.height / 2, {
                    halign: 'center',
                    valign: 'middle'
                });
                data.cursor.y += 20;
            } else if (row.index === 5) {
                doc.rect(data.settings.margin.left, row.y, data.table.width, 20, 'S');
                doc.autoTableText("Other Groups", data.settings.margin.left + data.table.width / 2, row.y + row.height / 2, {
                    halign: 'center',
                    valign: 'middle'
                });
                data.cursor.y += 20;
            }
        },
        drawCell: function (cell, data) {
            // Rowspan
            if (data.column.dataKey === 'id') {
                if (data.row.index % 5 === 0) {
                    doc.rect(cell.x, cell.y, data.table.width, cell.height * 5, 'S');
                    doc.autoTableText(data.row.index / 5 + 1 + '', cell.x + cell.width / 2, cell.y + cell.height * 5 / 2, {
                        halign: 'center',
                        valign: 'middle'
                    });
                }
                return false;
            }
        }
    });
    return doc;
};

/*
 |--------------------------------------------------------------------------
 | Below is some helper functions for the examples
 |--------------------------------------------------------------------------
 */

// Returns a new array each time to avoid pointer issues
var getColumns = function () {
    return [
        {title: "ID", dataKey: "id"},
        {title: "Name", dataKey: "first_name"},
        {title: "Email", dataKey: "email"},
        {title: "City", dataKey: "city"},
        {title: "Country", dataKey: "country"},
        {title: "Expenses", dataKey: "expenses"}
    ];
};

// Uses the faker.js library to get random data.
function getData(rowCount) {
    rowCount = rowCount || 4;
    var sentence = faker.lorem.words(12);
    var data = [];
    for (var j = 1; j <= rowCount; j++) {
        data.push({
            id: j,
            first_name: faker.name.findName(),
            email: faker.internet.email(),
            country: faker.address.country(),
            city: faker.address.city(),
            expenses: faker.finance.amount(),
            text: shuffleSentence(sentence),
            text2: shuffleSentence(sentence)
        });
    }
    return data;
}

function shuffleSentence(words) {
    words = words || faker.lorem.words(8);
    var str = faker.helpers.shuffle(words).join(' ').trim();
    return str.charAt(0).toUpperCase() + str.slice(1);
}

// Use http://dopiaza.org/tools/datauri or similar service to convert an image into image data
var headerImgData = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4g';
References:
https://simonbengtsson.github.io/jsPDF-AutoTable/#custom
https://github.com/simonbengtsson/jsPDF-AutoTable/tree/master/examples

Monday, June 13, 2016

How to use PDFMake to generate PDF under IE, Safari, and Android

PDFMake can be used to create pdf on client side. It worked nice under Chrome and Firefox, however, it doesn't work under IE, Safari, and Android. The reason it doesn't work because PDFMake simply created the pdf using a popup window to display it.

So to make it work, another javascript lib called PDF.js can be used. The PDF.js itself is a pdf viewer, and we can create a modal dialog to contain the pdf viewer, instead of using popup window.

Note PDF.js is not working with Safari, to get it working on Safari,
  1. compatibility.js must be included.
  2. PDFJS.workerSrc must be assigned.
<script type="text/javascript" src="compatibility.js"></script>
<script type="text/javascript" src="pdf.js"></script>

<!-- NEED THIS for Safari Mac to render work -->
<script type="text/javascript">
    // Specify the main script used to create a new PDF.JS web worker.  
    // In production, change this to point to the combined `pdf.js` file.  
    PDFJS.workerSrc = 'pdf.worker.js';  
</script>
HTML part:
The pdf.js actually use modal to display pdf content.
<div id="containerPDFViewer" class="modal modal-info fade" role="dialog">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
  <button type="button" class="close" data-dismiss="modal">&times;</button>
  <h4 class="modal-title">@GeneralResources.PDFViewer</h4>
            </div>
            <div class="modal-body">
  <canvas id="pdfviewer"></canvas>
            </div>
        </div>
        <!-- /.modal-content -->
    </div>
    <!-- /.modal-dialog -->
</div>
Javascript part:
//save the pdf into base64 strings
var pdfstr;
try {
    pdfMake.createPdf(docDefinition).getDataUrl(function (result) {   
        pdfstr = result;
        var pdfAsArray = convertDataURIToBinary(pdfstr);
        PDFJS.getDocument(pdfAsArray).then(function getPdf(pdf) {
            //  
            // Fetch the first page
            //  
            pdf.getPage(1).then(function getPdfPage(page) {
                var scale = 1.4;
                var viewport = page.getViewport(scale);
                //
                // Prepare canvas using PDF page dimensions
                //
                var canvas = $("#pdfviewer").get(0);
                var context = canvas.getContext('2d');
                canvas.height = viewport.height;
                canvas.width = viewport.width;           
                //
                // Render PDF page into canvas context
                //
                var renderContext = {
                    canvasContext: context,
                    viewport: viewport
                };
                page.render(renderContext);
                $('#containerPDFViewer').modal({ backdrop: 'static' }); //disable backdrop so user need to make choice
            });
        });
    });
}
catch (e) {     
    throw e;
}

var BASE64_MARKER = ';base64,';
function convertDataURIToBinary(dataURI) {
    var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
    var base64 = dataURI.substring(base64Index);
    var raw = window.atob(base64);
    var rawLength = raw.length;
    var array = new Uint8Array(new ArrayBuffer(rawLength));

    for (var i = 0; i < rawLength; i++) {
        array[i] = raw.charCodeAt(i);
    }
    return array;
}

Note the 1st parameter of getDataUrl is a call back function, will will be executed after getDataUrl is done. We need to put pdf.js code inside the call back function.

Here we didn't use getBase64 because it only return Base64 string, and getDataUrl actually returned Base64 string with leading pdf string. I have tested the code, the getBase64 failed to call convertDataURIToBinary() as there is base64 code error, but getDataUrl is OK.

Note as I tested, the pdf content will be displayed within the modal, but the effect is not as good as normal pdf viewer. In addition, even pdf.js still has issue in IE and Safari.

As result, for supporting IE and Safari, we should not use PDFMake and pdf.js.


References:
http://gonehybrid.com/how-to-create-and-display-a-pdf-file-in-your-ionic-app/
http://stackoverflow.com/questions/17022052/pdf-js-not-working-with-safari
http://stackoverflow.com/questions/12092633/pdf-js-rendering-a-pdf-file-using-a-base64-file-source-instead-of-url
https://developer.tizen.org/community/tip-tech/displaying-pdf-files-pdf.js-library


Tuesday, April 5, 2016

Creating PDF using Pdfmake - Advanced

Styling

pdfmake makes it possible to style any paragraph or its part:
var docDefinition = {
  content: [
    // if you don't need styles, you can use a simple string to define a paragraph
    'This is a standard paragraph, using default style',

    // using a { text: '...' } object lets you set styling properties
    { text: 'This paragraph will have a bigger font', fontSize: 15 },

    // if you set the value of text to an array instead of a string, you'll be able
    // to style any part individually
    {
      text: [
        'This paragraph is defined as an array of elements to make it possible to ',
        { text: 'restyle part of it and make it bigger ', fontSize: 15 },
        'than the rest.'
      ]
    }
  ]
};

Style dictionary

It's also possible to define a dictionary of reusable styles:
var docDefinition = {
  content: [
    { text: 'This is a header', style: 'header' },
    'No styling here, this is a standard paragraph',
    { text: 'Report No. 001', style: 'anotherstyle' },    { text: 'Created Date', style: [ 'header', 'anotherstyle' ] }
    { text: 'This is report body, style: 'textstyle' }  ],

  styles: {
    header: {
       fontSize: 22,
       bold: true,
       alignment: "center",
    },
    anotherstyle: {
       fontSize: 14,
       bold:true,
       alignment: 'right',
   },
   textstyle: {
       fontSize: 14,
       alignment: 'justify',
   }
};

Columns

By default paragraphs are rendered as a vertical stack of elements (one below another). It is possible however to divide available space into columns. Note Column content is not limited to a simple text. It can actually contain any valid pdfmake element.
var docDefinition = {
  content: [
    'This paragraph fills full width, as there are no columns. Next paragraph however consists of three columns',
    {
      columns: [
        {
          // auto-sized columns have their widths based on their content
          width: 'auto',
          text: 'First column'
        },
        {
          // star-sized columns fill the remaining space
          // if there's more than one star-column, available width is divided equally
          width: '*',
          text: 'Second column'
        },
        {
          // fixed width
          width: 100,
          text: 'Third column'
        },
        {
          // % width
          width: '20%',
          text: 'Fourth column'
        }
      ],
      // optional space between columns
      columnGap: 10
    },
    'This paragraph goes below all columns and has full width'
  ]
};

Tables

Conceptually tables are similar to columns. They can however have headers, borders and cells spanning over multiple columns/rows.
var docDefinition = {
    content: [
        {
            table: {
                // headers are automatically repeated if the table spans over multiple pages
                // you can declare how many rows should be treated as headers
                headerRows: 1,
                widths: [ '*', 'auto', 100, '*' ],
                body: [
                    [ 'First', 'Second', 'Third', 'The last one' ],
                    [ 'Value 1', 'Value 2', 'Value 3', 'Value 4' ],
                    [ { text: 'Bold value', bold: true }, 'Val 2', 'Val 3', 'Val 4' ]
                ]
            }
        }
    ]
};  

Styling tables 

You can provide a custom style for the table. Currently it supports: 
  • line widths 
  • line colors 
  • cell paddings
var styles = {
    header: {
        fontSize: 18,
        bold: true,
        margin: [0, 0, 0, 10]
    },
    subheader: {
        fontSize: 16,
        bold: true,
        margin: [0, 10, 0, 5]
    },
    tableExample: {
        margin: [0, 5, 0, 15]
    },
    tableHeader: {
        bold: true,
        fontSize: 13,
        color: 'black'
    }
};
    
var content = [
    { text: 'Tables', style: 'header' },
    { text: 'A simple table', style: 'subheader' },
    'The following table has nothing more than a body array',
    {
        style: 'tableExample',
        table: {
            body: [
                ['Column 1', 'Column 2', 'Column 3'],
                ['One value goes here', 'Another one here', 'OK?']
            ]
        }
    },
    { text: 'noBorders:', fontSize: 14, bold: true, pageBreak: 'before', margin: [0, 0, 0, 8] },
    {
        style: 'tableExample',
        table: {
            headerRows: 1,
            body: [
             [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3', 
style: 'tableHeader' }],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
            ]
        },
        layout: 'noBorders'
    },
    { text: 'headerLineOnly:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] },
    {
        style: 'tableExample',
        table: {
            headerRows: 1,
            body: [
             [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3', 
style: 'tableHeader' }],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
            ]
        },
        layout: 'headerLineOnly'
    },
    { text: 'lightHorizontalLines:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] },
    {
        style: 'tableExample',
        table: {
            headerRows: 1,
            body: [
             [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3', 

style: 'tableHeader' }],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
            ]
        },
        layout: 'lightHorizontalLines'
    },
    
    { text: 'but you can provide a custom styler as well', margin: [0, 20, 0, 8] },
    {
        style: 'tableExample',
        table: {
            headerRows: 1,
            body: [
             [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader'}, { text: 'Header 3', 
style: 'tableHeader' }],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
             [ 'Sample value 1', 'Sample value 2', 'Sample value 3' ],
            ]
        },
        layout: {
            hLineWidth: function(i, node) {
             return (i === 0 || i === node.table.body.length) ? 2 : 1;
            },
            vLineWidth: function(i, node) {
             return (i === 0 || i === node.table.widths.length) ? 2 : 1;
            },
            hLineColor: function(i, node) {
             return (i === 0 || i === node.table.body.length) ? 'black' : 'gray';
            },
            vLineColor: function(i, node) {
             return (i === 0 || i === node.table.widths.length) ? 'black' : 'gray';
            },
            // paddingLeft: function(i, node) { return 4; },
            // paddingRight: function(i, node) { return 4; },
            // paddingTop: function(i, node) { return 2; },
            // paddingBottom: function(i, node) { return 2; }
        }
    }
];
    
var docDefinition = {
    // a string or { width: number, height: number }
    pageSize: 'A4',
    // by default we use portrait, you can change it to landscape here
    pageOrientation: 'portrait', //can change to landscape
    // [left, top, right, bottom] or [horizontal, vertical] or just a number for equal margins
    pageMargins: [ 40, 60, 40, 60 ], 
    styles: styles,
    content: content,
    defaultStyle: {
        // alignment: 'justify'
    }    
};

Lists

pdfMake supports both numbered and bulleted lists:
var docDefinition = {
  content: [
    'Bulleted list example:',
    {
      // to treat a paragraph as a bulleted list, set an array of items under the ul key
      ul: [
        'Item 1',
        'Item 2',
        'Item 3',
        { text: 'Item 4', bold: true },
      ]
    },

    'Numbered list example:',
    {
      // for numbered lists set the ol key
      ol: [
        'Item 1',
        'Item 2',
        'Item 3'
      ]
    }
  ]
};

Headers and footers

Page headers and footers in pdfmake can be: static or dynamic.They use the same syntax:
var docDefinition = {
  header: 'simple text',

  footer: {
    columns: [
      'Left part',
      { text: 'Right part', alignment: 'right' }
    ]
  },

  content: (...)
};
For dynamically generated content (including page numbers and page count) you can pass a function to the header or footer:
var docDefinition = {
  footer: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount; },
  header: function(currentPage, pageCount) {
    // you can apply any logic and return any valid pdfmake element

    return { text: 'simple text', alignment: (currentPage % 2) ? 'left' : 'right' };
  },
  (...)
};

Background-layer

The background-layer will be added on every page.
var docDefinition = {
  background: 'simple text',

  content: (...)
};
It may contain any other object as well (images, tables, ...) or be dynamically generated:
var docDefinition = {
  background: function(currentPage) {
    return 'simple text on page ' + currentPage
  },

  content: (...)
};

Margins

Any element in pdfMake can have a margin:
(...)
// margin: [left, top, right, bottom]
{ text: 'sample', margin: [ 5, 2, 10, 20 ] },

// margin: [horizontal, vertical]
{ text: 'another text', margin: [5, 2] },

// margin: equalLeftTopRightBottom
{ text: 'last one', margin: 5 }
(...)

Stack of paragraphs

You could have figured out by now (from the examples), that if you set the content key to an array, the document becomes a stack of paragraphs. You'll quite often reuse this structure in a nested element, like in the following example:
var docDefinition = {
  content: [
    'paragraph 1',
    'paragraph 2',
    {
      columns: [
        'first column is a simple text',
        [
          // second column consists of paragraphs
          'paragraph A',
          'paragraph B',
          'these paragraphs will be rendered one below another inside the column'
        ]
      ]
    }
  ]
};
The problem with an array is that you cannot add styling properties to it (to change font size for example). The good news is - array is just a shortcut in pdfMake for { stack: [] }, so if you want to restyle the whole stack, you can do it using the expanded definition:
var docDefinition = {
  content: [
    'paragraph 1',
    'paragraph 2',
    {
      columns: [
        'first column is a simple text',
        {
          stack: [
            // second column consists of paragraphs
            'paragraph A',
            'paragraph B',
            'these paragraphs will be rendered one below another inside the column'
          ],
          fontSize: 15
        }
      ]
    }
  ]
};

Images

This is simple. Just use the { image: '...' } node type. JPEG and PNG formats are supported.
var docDefinition = {
  content: [
    {
      // you'll most often use dataURI images on the browser side
      // if no width/height/fit is provided, the original size will be used
      image: 'data:image/jpeg;base64,...encodedContent...'
    },
    {
      // if you specify width, image will scale proportionally
      image: 'data:image/jpeg;base64,...encodedContent...',
      width: 150
    },
    {
      // if you specify both width and height - image will be stretched
      image: 'data:image/jpeg;base64,...encodedContent...',
      width: 150,
      height: 150
    },
    {
      // you can also fit the image inside a rectangle
      image: 'data:image/jpeg;base64,...encodedContent...',
      fit: [100, 100]
    },
    {
      // if you reuse the same image in multiple nodes,
      // you should put it to to images dictionary and reference it by name
      image: 'mySuperImage'
    },
    {
      // under NodeJS (or in case you use virtual file system provided by pdfmake)
      // you can also pass file names here
      image: 'myImageDictionary/image1.jpg'
    }
  ],

  images: {
    mySuperImage: 'data:image/jpeg;base64,...content...'
  }
};

Page dimensions, orientation and margins

var docDefinition = {
  // a string or { width: number, height: number }
  pageSize: 'A5',

  // by default we use portrait, you can change it to landscape if you wish
  pageOrientation: 'landscape',

  // [left, top, right, bottom] or [horizontal, vertical] or just a number for equal margins
  pageMargins: [ 40, 60, 40, 60 ],
};
If you set pageSize to a string, you can use one of the following values:
  • '4A0', '2A0', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
  • 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
  • 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10',
  • 'RA0', 'RA1', 'RA2', 'RA3', 'RA4',
  • 'SRA0', 'SRA1', 'SRA2', 'SRA3', 'SRA4',
  • 'EXECUTIVE', 'FOLIO', 'LEGAL', 'LETTER', 'TABLOID'
To change page orientation within a document, add a page break with the new page orientation.
{
  pageOrientation: 'portrait',
  content: [
    {text: 'Text on Portrait'},
    {text: 'Text on Landscape', pageOrientation: 'landscape', pageBreak: 'before'},
    {text: 'Text on Landscape 2', pageOrientation: 'portrait', pageBreak: 'after'},
    {text: 'Text on Portrait 2'},
  ]
}

Document Metadata

PDF documents can have various metadata associated with them, such as the title, or author of the document. You can add that information by adding it to the document definition
var docDefinition = {
  info: {
    title: 'awesome Document',
    author: 'john doe',
    subject: 'subject of document',
    keywords: 'keywords for document',
  },
  content:  'This is an sample PDF printed with pdfMake' 
}

Source: 

Creating PDF using Pdfmake - Introduction

Pdfmake follows a declarative approach. You don't need to calculate positions manually like: writeText(text, x, y), moveDown etc..., as you other libraries do.

You just need to create document-definition-object like this:
var docDefinition = { content: 'This is an sample PDF printed with pdfMake' };

You can add more stuffs to the object with multi-level tables, images, lists, paragraphs, margins, styles etc.  After you made the object, you can create the pdf and download it.

// open the PDF in a new window
pdfMake.createPdf(docDefinition).open();
// print the PDF (not working in this version, will be added back in a couple of days)
// pdfMake.createPdf(docDefinition).print();
// download the PDF
pdfMake.createPdf(docDefinition).download();

Pdfmake has following features:
  • line-wrapping,
  • text-alignments (left, right, centered, justified),
  • numbered and bulleted lists,
  • tables and columns
    • auto/fixed/star-sized widths,
    • col-spans and row-spans,
    • headers automatically repeated in case of a page-break,
  • images and vector graphics,
  • convenient styling and style inheritance,
  • page headers and footers:
    • static or dynamic content,
    • access to current page number and page count,
  • background-layer
  • page dimensions and orientations,
  • margins,
  • custom page breaks,
  • font embedding,
  • support for complex, multi-level (nested) structures,
  • helper methods for opening/printing/downloading the generated PDF.
  • setting of PDF metadata (e.g. author, subject)
Source: