One thing that would enable more scaling client-side scenarios would be if pdfMake can run in a web worker compatible mode. One thing I'm seeing with more complex PDFs in IE and Firefox is script time outs, which probably is to be expected if most of the logic runs on the UI thread.
Trying to use from a web worker just to see how many dependencies on window DOM, initially get errors in sections of pdfmake.js using the window.navigator object.
in pdfWebWorker.js importScripts fails. Thinking it might be possible to put shim components before invoking importScripts in the web worker....or fork and create custom build of pdfmake...
importScripts("pdfmake.js", "vfs_fonts.js");
(Thought maybe it had a chance if the same source code was managing to run on node.js there couldn't be that many dependencies on DOM.)
Great tool so far. Thanks.
Great idea!!! BTW - could you share a sample doc-definition-object which causes the script timeout? I'm getting back to pdfmake after a long break and I'm trying to focus on the first milestone (performance improvements).
Sure, gladly. Part of the initial timeout was that I am using other cpu intensive scripts (vis.js and html2canvas) and pdfmake is the last set of scripts in the pipeline. So it doesn’t always seem consistent in causing timeout.
I get this in firefox, and intermittently in IE:
“A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete.
Script: http://localhost:52165/Scripts/pdfmake.js:3813” Thanks!
var docDefinition = {
content: [
{
columns: [
{
// if you specify width, image will scale proportionally
image: 'companyLogo',
width: 150
},
{ text: 'SummarySummary Summary', style: 'header' }
],
// optional space between columns
columnGap: 10
}
,
{
table: {
// headers are automatically repeated if the table spans over multiple pages
// you can declare how many rows should be treated as headers
headerRows: 0,
widths: ['*', '*'],
style: 'tbl',
body: [
[{
stack: [{ text: [{ text: 'XYZ:', bold: true }, { text: "lorem ipsum" }], style: 'field' },
{ text: [{ text: 'ABC:', bold: true }, { text: "lorem ipsum" }], style: 'field' },
{ text: [{ text: '123:', bold: true }, { text: "lorem ipsum" }], style: 'field' },
]
}, { text: 'Patient Name:' }]
]
}
},
//{
// canvas: [
// {
// type: 'rect',
// x: 0,
// y: 0,
// w: 600,
// h: 260,
// r: 5,
// dash: { length: 2 },
// // lineWidth: 10,
// lineColor: 'blue',
// fillOpacity: .7,
// strokeOpacity: 1
// }]
//},
{
image: 'patientTimeline'
//width:680
},
{
columns: [
{
// auto-sized columns have their widths based on their content
width: '*',
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'
},
{
// star-sized columns fill the remaining space
// if there's more than one star-column, available width is divided equally
width: '*',
text: '3 column'
}
],
// optional space between columns
columnGap: 10
}
],
styles: {
header: {
fontSize: 16,
bold: true,
color: 'blue',
alignment: 'center'
},
field: {
fontSize: 10,
alignment: 'justify'
},
tbl: {
hLineColor: 'blue',
vLineColor: 'blue',
vLineWidth: 2,
hLineWidth: 2
}
},
images: {
patientTimeline: 'data:image/png;base64,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AAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAg0nX/D3xkbxtHv5JbAAAAAElFTkSuQmCC',
companyLogo: 'data:image/png;base64,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AAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAgJKwCAAAAAISEVQAAAACAkLAKAAAAABASVgEAAAAAQsIqAAAAAEBIWAUAAAAACAmrAAAAAAAhYRUAAAAAICSsAgAAAACEhFUAAAAAgJCwCgAAAAAQElYBAAAAAELCKgAAAABASFgFAAAAAAgJqwAAAAAAIWEVAAAAACAkrAIAAAAAhIRVAAAAAICQsAoAAAAAEBJWAQAAAABCwioAAAAAQEhYBQAAAAAICasAAAAAACFhFQAAAAAg0nX/D3xkbxtHv5JbAAAAAElFTkSuQmCC'
}
};
Daniel Lesser | Technical Director, Business Performance Services | NTT DATA, Inc. | m. +1.303.808.5731 | daniel.[email protected]:daniel.[email protected] | NTT DATA Americashttp://americas.nttdata.com/ | Twitter: @https://twitter.com/#!/NTTDAmericasASNTTDAmericasAS | LinkedIn: NTTDATAAmericashttp://www.linkedin.com/company/ntt-data-americas
From: bpampuch [mailto:[email protected]]
Sent: Friday, June 13, 2014 11:49 AM
To: bpampuch/pdfmake
Cc: Lesser, Daniel
Subject: Re: [pdfmake] Clientside Feature Suggestion: Web Worker Compatibility (#38)
Great idea!!! BTW - could you share a sample doc-definition-object which causes the script timeout? I'm getting back to pdfmake after a long break and I'm trying to focus on the first milestone (performance improvements).
—
Reply to this email directly or view it on GitHubhttps://github.com/bpampuch/pdfmake/issues/38#issuecomment-46040264.
Disclaimer:This email and any attachments are sent in strictest confidence for the sole use of the addressee and may contain legally privileged, confidential, and proprietary data. If you are not the intended recipient, please advise the sender by replying promptly to this email and then delete and destroy this email and any attachments without any further use, copying or forwarding
Hello - We are considering using pdfmake to generate one page reports and we are concerned with performance. We are generating simple one page PDF that is 50Kbyte that mostly contain one PNG generated by Google chart that is 20Kbyte. The generation of such a report can take up to 30 second!! We tried to profile that but with no success for now. Any hint about how to profile PDFmake doc generation? If we cannot optimize, we will consider using web worker and at least unfreeze the UI
+1, I need to generate a report of ~1mb and it takes around 5 seconds, which is quite long when the UI freeze.
I am actually trying to do my custom web worker integration in my angular application, but would be awesome to see this functionality embedded in pdfmake
We would be happy to accept a pull request ;-)
I'll start by learning how webworkers work exactly :) but why not, I'll take a look.
For now the problem is the fileSaver lib which use view.document directive which isn't allowed in web workers, any idea how to solve this ?
The filesaver is (surprise) for saving/downloading files - this will need
user interaction anyway and therefore cannot be done in a web worker.
So my approach would be to split the generation of the PDF and the handling
of its output - download, open and so on. Then the 'slow' generation is
done, while the interaction stays in the browser.
Make sure to create integration tests which indicate when someone
accidentally breaks web worker compatibility again.
Best regards
Johannes
Am 27.03.2015 10:48 schrieb "kitensei" [email protected]:
I'll start by learning how webworkers work exactly :) but why not, I'll
take a look.
For now the problem is the fileSaver lib which use view.document
directive which isn't allowed in web workers, any idea how to solve this ?—
Reply to this email directly or view it on GitHub
https://github.com/bpampuch/pdfmake/issues/38#issuecomment-86882582.
Hi all -- I've started looking into this one for my own nefarious porpoises. So it looks like, for web workers, you can throw just about anything 'over the wall' between the main thread and the web worker via a postMessage so long as it's serializable. So: no functions, no circular references.
So I'm guessing on the input end, I can throw in the doc object -- it's a big object, but it's serializable. And then on the other end, the web worker could get the buffer back -- again, huge, but serializable.
So then the web worker could respond to a message with a doc object by calling _createDoc, and making the callback a postMessage that sends the resulting buffer back to the main thread.
Then the toughest part is figuring out how to import some subset of pdfMake that a web worker can successfully run. Maybe it just imports all of pdfMake, and I pepper pdfMake with guards against running in not-a-window?
Does this sound vaguely sane?
Huh -- I kind of have it working, to my surprise. The (giant) drawback is that your document object -- the content, the footers, and whatnot -- can't include any function definitions, because those can't be serialized. This might be an insuperable problem.
Yes, that's true.
Very cool. But is it not possible to eval() within a webworker? Didn't turn up anything on stack overflow so guess have to experiment. And translate to obj= {'functionName':'functionAsString'} - > translate to webWorkerObj[functionName]=function(){eval(obj.functionName)} ... it may be too tricky even if this works in principal.
Example #1: Create a generic "asynchronous eval()" -
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Example_.231.3A_Create_a_generic_.22asynchronous_eval().22
Ooh, interesting idea. I'm also wondering if it's possible to pass along a filename, put an object that maps names to functions in that file:
{
specialFooter: function() {
return (new Date()).toString();
}
}
... and then have pdfMake import that file as a module, and then replace mentions of that function name with the function itself:
footer: {
functionName: "specialFooter"
}
... not sure if that'd work, though.
For my project, I'm most likely going to:
registerDefaultTableLayouts, including one for horizontal rules.Between those two, I shouldn't have to pass in any functions (fingers crossed).
If it's anything like messages to frames, it should be almost trivial to make many functions "callable" from across the wall.
// fn is a string containing method name
function handleMsg(evt) {
if (evt.data && evt.data.fn)
pdfMake[evt.data.fn]()
}
window.addEventListener('message', handleMsg, false)
Yup -- the main issue is making sure there aren't any functions in the doc object. Plus there are a few adjustments to make to the pdfmake code itself, so it doesn't freak out about being called in a web-worker situation.
Note that pdfmake in a web work isn't working when deployed to iOS Safari, because of this issue: https://github.com/lodash/lodash/issues/313
I can run pdfmake in webworker. It is stupid:
var document = { 'createElementNS': function(){ return {}; } };
The offending code calls documentcreateElementNS, but it is not really used.
I just return a dummy JS object - not even an Element - and it happily gives me a pdf!
It is not that hard to update the code to support web worker, or is it?
P.S. vfs_fonts.js use window, unavailable in worker, which is also... easy to fix.
I have a tidy workaround to avoid passing the footer as a function. First, I transform the footer function in a footer template:
Instead of:
footer : function (currentPage, pageCount) { return currentPage' + ' of ' + pageCount}),
I write:
footerTpl : '{{currentPage}}' + ' of ' + '{{pageCount}}',
Then I prepare the whole pdfTemplate and send it to the web worker, so in worker.js I parse the footer string into the real footer:
self.onmessage = function (e) {
if (e.data.footerTpl) {
e.data.footer = function (currentPage, pageCount) {
var footer = e.data.footerTpl.replace('{{currentPage}}', currentPage);
footer = footer.replace('{{pageCount}}', pageCount);
return footer;
};
}
pdfMake.createPdf(e.data).getBase64(function (base64) {
self.postMessage(base64);
});
};
And you have a nice PDF with page count on footer.
Hi dlesser.
How are you?
I would like to discuss with you about vfs_fonts.js problem in web worker.
I used the solution of Sheep-y and resolved pdfmake.js importing problem but vfs_font.js is not working in web worker.
Would you let me know the solution?
I think you already resolved completely.
Thanks.
Sasha
Sorry don't have it...I ended up using server side solution.
I've managed to make web worker work reasonably well with pdfmake, demo code: https://gist.github.com/leedongwei/6015450165b70a32b72cdebc073714ab
@bpampuch If this looks like a reasonable workaround, I'll make a pull request to update the documentation.
@leedongwei Any help is welcome. But first we should solve the incompatibility with web worker inside pdfmake.
My findings and suggestions:
Problem 1:
window = this;
pdfmake using window property which is only in the browser. I can fix it, I use global instead of window (in vfs_fonts.js file probably this).
Problem 2:
document = { createElementNS: function () { return {}; } };
createElementNS is used in external library FileSaver.js, see: https://github.com/eligrey/FileSaver.js/blob/aa9f4e0e03bd1892482ff5e24ca91d42312dbf18/FileSaver.js#L28
Is used to download a file, in web worker is not used but is in source file. I don't know how solve it now. But I try it.
Big problem 3:
Problem with functions - https://github.com/bpampuch/pdfmake/issues/38#issuecomment-229358463
If I can send message to worker is needed convert it to string, because only a string can be sent. Can not be send as myWorker.postMessage(docDefinition). docDefinition must be converted to string: myWorker.postMessage( JSON.stringify(docDefinition) );, but JSON.stringify not support functions.
_Solution:_
Make another string converter with support functions implemented in pdfmake.
During creation Worker in script, I suppose is not good include full pdfmake script? So we need to do another script file with class - pdfMakePreparer (Any better ideas?), which will only allow safely convert docDefinition to string or/and call postMessage on Worker with stringDocDefinition.
And in worker skript will be used standard pdfmake method pdfMake.createPdf( dd ), where createPdf if they receive docDefiniton as string through safety convert string to docDefinition.
Examples:
var docDefinition = {
// ... standard docDefinition
}
myWorker = new Worker('worker.js');
pdfMakePreparer.postMessage(myWorker, docDefinition); // internaly this make convert docDefinition to string with own JSON.stringify and call myWorker.postMessage(stringDocDefinition);
// or
var stringDocDefinition = pdfMakePreparer.prepareDocDefinition(docDefinition); // only internaly convert
myWorker.postMessage(stringDocDefinition );
worker.js:
onmessage = function(e) {
// If is e.data as string make transform with own JSON.parse from string to docDefinition inside createPdf
var doc = pdfMake.createPdf(e.data)
doc.getBlob();
// etc.
};
I saw that guys in the project OpenSlides using web worker with this hacks - https://github.com/OpenSlides/OpenSlides/blob/935a2a724544d0be89b6d143488cd649712cd068/openslides/core/static/js/core/pdf-worker.js , @emanuelschuetze and @tsiegleauq any ideas or feedback for the proposed solutions?
And all, any other ideas?
I am on phone and cannot use @ function.
Somebody please @'s Finn Stutzenstein from
OpenSlides.
On Apr 20, 2017 11:16, "Libor M." notifications@github.com wrote:
@leedongwei https://github.com/leedongwei Any help is welcome. But
first we should solve the incompatibility with web worker inside pdfmake.My findings and suggestions:
Problem 1:
window = this;
pdfmake using window property which is only in the browser. I can fix it,
I use global instead of window (in vfs_fonts.js file probably this).
Problem 2:
document = { createElementNS: function () { return {}; } };
createElementNS is used in external library FileSaver.js, see:
https://github.com/eligrey/FileSaver.js/blob/
aa9f4e0e03bd1892482ff5e24ca91d42312dbf18/FileSaver.js#L28
Is used to download a file, in web worker is not used but is in sourcefile. I don't know how solve it now. But I try it.
Big problem 3:
Problem with functions - #38 (comment)
https://github.com/bpampuch/pdfmake/issues/38#issuecomment-229358463
If I can send message to worker is needed convert it to string, because
only a string can be sent. Can not be send as myWorker.postMessage(
docDefinition). docDefinition must be converted to string: myWorker.postMessage(
JSON.stringify(docDefinition) );, but JSON.stringify not support
functions.Solution:
Make another string converter with support functions implemented in
pdfmake.During creation Worker in script, I suppose is not good include full
pdfmake script? So we need to do another script file with class -
pdfMakePreparer (Any better ideas?), which will only allow safely convert
docDefinition to string or/and call postMessage on Worker with
stringDocDefinition.
And in worker skript will be used standard pdfmake method pdfMake.createPdf(
dd ), where createPdf if they receive docDefiniton as string through
safety convert string to docDefinition.Examples:
var docDefinition = {
// ... standard docDefinition
}myWorker = new Worker('worker.js');
pdfMakePreparer.postMessage(myWorker, docDefinition); // internaly this make convert docDefinition to string with own JSON.stringify and call myWorker.postMessage(stringDocDefinition);
// or
var stringDocDefinition = pdfMakePreparer.prepareDocDefinition(docDefinition); // only internaly convert
myWorker.postMessage(stringDocDefinition );worker.js:
onmessage = function(e) {
// If is e.data as string make transform with own JSON.parse from string to docDefinition inside createPdf
var doc = pdfMake.createPdf(e.data)
doc.getBlob();
// etc.
};
I saw that guys in the project OpenSlides using web worker with this hacks
- https://github.com/OpenSlides/OpenSlides/blob/
935a2a724544d0be89b6d143488cd649712cd068/openslides/core/
static/js/core/pdf-worker.js , @emanuelschuetze
https://github.com/emanuelschuetze and @tsiegleauq
https://github.com/tsiegleauq any ideas or feedback for the proposed
solutions?And all, any other ideas?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/bpampuch/pdfmake/issues/38#issuecomment-295646625,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AJwkyDGwD6jrlk7abIl-uI-Gb9_4xvZaks5rxyJsgaJpZM4CEFpJ
.
@FinnStutzenstein ping ;-)
Hi
Yes, we at OpenSlides use exactly these three hacks to use PdfMake within web workers.
Should be easy to fix.
To use WebWorkers you have to have (at least) two scripts. In the WebWorker script just the casting from docDefinition --> blob/b64/.. is done. So the worker script has not to include FileSaver.
Also for a production use this is helpful, because you may handle these two js files different. The worker script should not be squashed together in the main js sourcemap, but rather stay alone.
Use eval. Our team thought about that, because the functions passe dare very small and simple. But there are two main reasons against eval:
eval is a huge security issue.Templates: Our current solution, as we cannot pass functions. Not very nice, but just for the two places, it's ok. -> Not ok for a upstream solution.
Do some prerendering. Convert the docDefinition in something serialize able, what has to be fully rendered in the worker. This should not take a long time. Unfortunately, I've not looked very deep in the PdfMake source, that I can evaluate, if this is a good option. But, as a fact, we have to get a string, so some pre evaluating has to be done here.
If this is implemented, PdfMake should hide the WebWorkers by just giving the option, to generate the pdf async. A setting to specify the worker filename would be great. And two separate files are necessary and the worder script should not contain the whole PdfMake source.
@FinnStutzenstein Hi. Thanks for your experiences and ideas.
As first step i'm fixed compatibility with running in worker script (solves problem 1 and temporally problem 2), commits: https://github.com/bpampuch/pdfmake/commit/5fd7bc9fa3d13014bfc3797cd7f50935f363bcd0, https://github.com/bpampuch/pdfmake/commit/33df9bbec76b358bec8d08bc49a1d2892445a3fa.
I will try to think about a complex solution with support functions. And possibly any pdfmake async class/script.
Any one can provide an example on how to use pdfMake in a web-worker in angular 4?
Thanks.
@liborm85
Big problem 3:
Problem with functions - #38 (comment)
If I can send message to worker is needed convert it to string, because only a string can be sent. Can not be send as myWorker.postMessage(docDefinition). docDefinition must be converted to string: myWorker.postMessage( JSON.stringify(docDefinition) );, but JSON.stringify not support functions.
If you are creating the full doc definition outside the web worker, why do you need pdfmake at all inside the worker? Why not just message over a url blob of the complete pdf?
If you are creating the full doc definition outside the web worker, why do you need pdfmake at all inside the worker? Why not just message over a url blob of the complete pdf?
Did I get you right that you want to create the pdf blob outside of the worker and just pass the url to the worker? If so, you get this wrong: The creation of the doc definition is fast; we want to source out the converting json->pdf (doc definition -> blob/b64) in fact that this can took several minutes. For this conversion we need like 98% of pdfmake (except the download thing) inside of the web worker. The creation of the doc definition has nothing to do with pdfmake. This is just placing javascript arrays and objects with data in the right format that pdfmake can parse this.