javascript - How to apply web worker to rendering of a PDF using makepdf -


i created pdf using javascript plug-in (pdfmake) , great. when try render ~8,000-row inventory/ledger printout, freeze on minute.

this how declare docdefinition

var docdefinition = {  pageorientation: orientation,  footer: function(currentpage, pagecount) { return {text: currentpage.tostring() + ' / ' + pagecount, fontsize:8, alignment:'center'}; },  content:[     printheader,    { fontsize: 8, alignment: 'right', style: 'tableexample',     table: {         widths: width,         headerrows: 1, body: arr },     layout: 'lighthorizontallines' }] } 

where

var printheader =   [ { text: 'company name',alignment:'center' }, { text: 'address 1',alignment:'center' }, { text: 'address 2',alignment:'center' }, { text: 'additional details,alignment:'center' }, { text: 'document title',alignment:'center' }]; 

and

 var arr = [[{"text":"","alignment":"left"},"text":"date","alignment":"left"}, {"text":"trans #","alignment":"left"},{"text":"description","alignment":"left"}, {"text":"ref #","alignment":"left"},{"text":"debit","alignment":"left"}, {"text":"credit","alignment":"left"},{"text":"amount","alignment":"left"}, {"text":"balance","alignment":"left"}],[{"text":"account : merchandise inventory","alignment":"left","colspan":8},"","","","","","","", {"text":"1,646,101.06"}],["","10/13/2015","st#0094",{"text":"","alignment":"left"},{"text":"","alignment":"left"},"546.94","0.00","546.94","1,646,648.00"],[{"text":"total","alignment":"left","bold":true},"","","","", {"text":"546.94","alignment":"right","bold":true}, {"text":"0.00","alignment":"right","bold":true}, {"text":"","alignment":"right","bold":true}, {"text":"546.94","alignment":"right","bold":true}],[{"text":"account : accounts payable-main","alignment":"left","colspan":8},"","","","","","","", {"text":"-1,741,953.62"}],["","10/13/2015","st#0094", {"text":"","alignment":"left"}, {"text":"","alignment":"left"},"0.00","546.94","-546.94","-1,742,500.56"], [{"text":"total","alignment":"left","bold":true},"","","","", {"text":"0.00","alignment":"right","bold":true}, {"text":"546.94","alignment":"right","bold":true}, {"text":"","alignment":"right","bold":true}, {"text":"-546.94","alignment":"right","bold":true}] 

generated file.

i searched web workers , see can solve ui freezing problem. tried create web worker it:

$('#makepdf').click(function(){     var worker = new worker("<?php echo url::to('/'); ?>/js/worker.js");   worker.addeventlistener('message',function(e){   console.log('worker said: ',e.data); },false);  worker.postmessage(docdefinition); 

//worker.js

self.addeventlistener('message', function(e) {   self.postmessage(e.data); }, false); 

output console.log():

worker said: object {pageorientation: "portrait", content: array[7]} logging correctly json structure.

so far good. after added pdfmake.min.js , vfs_font.js worker, error uncaught typeerror: cannot read property 'createelementns' of undefined.

i error before started using worker.

is possible implement web workers pdfmake plug-in?

simple answer

just provide dummy constructor:

var document = { 'createelementns': function(){ return {} } }; var window = this; importscripts( 'pdfmake.min.js', 'vfs_fonts.js' ); 

alternatively, if think dirty, import xml-js (only 60k) , create virtual document pdfmake.

importscripts( 'tinyxmlw3cdom.js' ); var window = this; var document = new domdocument( new domimplementation() ); importscripts( 'pdfmake.min.js', 'vfs_fonts.js' ); 

explanation

pdfmake known incompatible worker.

by itself, pdfmake does not use createelementns. minified script pdfmake.min.js do, apparently create download link.

we don't need download link anyway, give dummy keep happy (for now).

if in future needs real dom, bad news document unavailable in web worker. news have pure javascript implementation. download xml-js, extract , find tinyxmlw3cdom.js, import , can create functional document.

in addition document, since vfs_fonts.js pdfmake through window variable, need introduce window alias global.

for me, these steps make pdfmake works in web worker.

to save file, need convert base64 data provided pdfmake binary download. number of scripts available, such download.js. in code below using filesaver.


code

my worker builder can cached. if compose worker on server side, can rid of stack , build functions , directly call pdfmake, making both js code simpler.

main html:

<script src='filesaver.min.js'></script> <script> function base64toblob( base64, type ) {     var bytes = atob( base64 ), len = bytes.length;     var buffer = new arraybuffer( len ), view = new uint8array( buffer );     ( var i=0 ; < len ; i++ )       view[i] = bytes.charcodeat(i) & 0xff;     return new blob( [ buffer ], { type: type } ); } //////////////////////////////////////////////////////////  var pdfworker = new worker( 'worker.js' );  pdfworker.onmessage = function( evt ) {    // open( 'data:application/pdf;base64,' + evt.data.base64 ); // popup pdf    saveas( base64toblob( evt.data.base64, 'application/pdf' ), 'general ledger.pdf' ); };  function pdf( action, data ) {    pdfworker.postmessage( { action: action, data: data } ); }  pdf( 'add', 'hello webworker' ); pdf( 'add_table', { headerrows: 1 } ); pdf( 'add', [ 'first', 'second', 'third', 'the last one' ] ); pdf( 'add', [ { text: 'bold value', bold: true }, 'val 2', 'val 3', 'val 4' ] ); pdf( 'close_table' ); pdf( 'add', { text: 'this paragraph have bigger font', fontsize: 15 } ); pdf( 'gen_pdf' ); // triggers onmessage when done  // alternative, one-size-fit-all usage pdf( 'set', { pageorientation: 'landscape', footer: { text: 'copyright 2015', fontsize: 8, alignment:'center'}, content:[ "header", { fontsize: 8, alignment: 'right', table: { headerrows: 1, body: [[1,2,3],[4,5,6]] } }] } ); pdf( 'gen_pdf' );  </script> 

worker:

//importscripts( 'tinyxmlw3cdom.js' ); //var document = new domdocument( new domimplementation() ); var document = { 'createelementns': function(){ return {} } }; var window = this; importscripts( 'pdfmake.min.js', 'vfs_fonts.js' );  (function() { 'use strict';  var doc, current, context_stack;  function set ( data ) {    doc = data;    if ( ! doc.content ) doc.content = [];    current = doc.content;    context_stack = [ current ]; } set( {} );  function add ( data ) {    current.push( data ); }  function add_table ( template ) {    if ( ! template ) template = {};    if ( ! template.table ) template = { table: template };    if ( ! template.table.body ) template.table.body = [];    current.push( template ); // append table    push( template.table.body ); // switch context table body }  function push ( data ) {    context_stack.push( current );    return current = data; }  function pop () {    if ( context_stack.length <= 1 ) return console.warn( "cannot close pdf root" );    context_stack.length -= 1;    return current = context_stack[ context_stack.length-1 ]; }  function gen_pdf() {    pdfmake.createpdf( doc ).getbase64( function( base64 ) {       postmessage( { action: 'gen_pdf', base64: base64 } );    } ); }  onmessage = function( evt ) {    var action = evt.data.action, data = evt.data.data;    switch ( action ) {       case 'set': set( data ); break;       case 'add': add( data ); break;       case 'add_table'  : add_table( data ); break;       case 'close_table': pop(); break;       case 'gen_pdf': gen_pdf(); break;    } };  })(); 

Comments

Popular posts from this blog

java - Date formats difference between yyyy-MM-dd'T'HH:mm:ss and yyyy-MM-dd'T'HH:mm:ssXXX -

c# - Get rid of xmlns attribute when adding node to existing xml -