Documentation for PDFColumns

By Stephen Joys Aug 11th 2020

PDF Columns is wrapper for jsPDF that is still written as code but has an easier document formating system to produce clean PDF documents with autobuilt columns, styles and images. while jsPDF does not allow for zorder of printing, this app can work around it and print images and background colors behind text

In this first example, let's create a new document, add a background image, add some text and save.
	//starting document
	  
		let pdf = new PDFColumns("filename");
		await PDFLoadImage(pdf,'background',"back_image.png");
		await PDFLoadImage(pdf,'robocat',"doraemon.png");
	
		pdf.dim.left= 14; //adjust the margins before adding pages
	
		//add background before loading first page;
        
		// add a page with auto-numbering and background
		pdf.newPage();
                
			// writes following main page dimensions set in pdf.dim
			pdf.nline("here is some text");
			pdf.nline("and some more");
				
			pdf.cimage("robocat");
	               
		pdf.save(); //opens download dialog for user to get the file
	


Adding columns to document

Next we can add down-flowing columns to the document: this code creates a new PDFColumns document and uses the col() or 'columns' to generate two side-by-side columns for writing
	
		let pdf = new PDFColumns("filename");
		
		pdf.newPage(); //do variable loading as above
	
			pdf.col(2);	// create two side by side columns of equal size total 100% of print range
		
					pdf.nline("write text in first column");
					pdf.nline("keep writing next line down on same column");
		
				pdf.next(); //swaps to next col in this group
		
					pdf.nline("write text in the second column at its starting point");
		
				pdf.next(); //cycle back to the first column);

			pdf.end();
			
		pdf.save();
	


Nested columns

We can also nest columns infinitely. in this example we will create a set of 3 columns in the first large column. Some flags are sent with the text to allign the text in the middle
	let pdf = new PDFColumns("filename",{align:"center"});
	pdf.newPage();
	
	pdf.nline("document title at top of page");
	pdf.col(2);     // create two side by side columns of equal size total 100% of print range
		pdf.nline("below are nested columns");
		
		pdf.col(3,[2,5,5]); // 3 columns spliting parent column space in ratio 2,5,5
			pdf.nline("1st small",{align:"center"});
			pdf.nline("data 1",{align:"center"});
		pdf.next();
			pdf.nline("2nd column",{align:"center"});
			pdf.nline("data 2",{align:"center"});
		pdf.next();
			pdf.nline("3rd Column",{align:"center"});
			pdf.nline("data 3",{align:"center"});
		pdf.end();
		
		pdf.next(); //back to top columns set
		
		//lets make a grid using arrays
		pdf.col(4);
		for(let i = 0;i<4;i++){
			for(let j = 0;j<4;j++){
				pdf.nline(""+(i*4+j+1));
				pdf.next();
			}
		}
		pdf.end();

	pdf.end();

pdf.save();


Styles

Next the formatting avaliable for jsPDF, like text color, font, size, line color, etc. has been organized into 3 functions that can save collections of styles by name and apply new or saved styles quickly
	// create a style but dont apply it, simply save it as default to be accessed later
	// by virtue of being the first one given by the user, this is set as default
        pdf.addStyle({name:"mytext",font:"verdana",fontsize:10,fontstyle:"bold", color:"#000000"});
        
        pdf.style();				//applies last kept style as single 'previous style' (no full history)
			pdf.nline("style();");
		
		pdf.style("mytext");		//applies named style saved previously, keeps this style as fallback
			pdf.nline("mytext");
		
		pdf.style({color:"#0000FF"},1);		// applies new style, doesn't save as fallback
			pdf.nline("red");
		pdf.style();						//returns to previous
			pdf.nline("black like mytext again");
		
		pdf.style({name:"newstyle", {color:"#0000FF"});	//saves, applies, and saves as fallback
		
		
		pdf.style({fontsize:14});	// applies, and saves as fallback
        
                // applying styles does nothing to keys not present, so clearing styles means
                // applying a style with all keys accounted for (user could make a detailed style called "default")
                // and apply that to clean out the odd spacing or colors
        
		pdf.nline("this text is altered by last styles applied");


Border and Fill

Another type of style tag are border and fillcolor, that affects currently active column and unlike jsPDF will be correctly applied behind flowing text and images after everything is written
		pdf.col(2);
				pdf.style({border:"#00FF00"});  // this style is fixed onto the active column
				pdf.nline("this column will be bordered by a colored box");
			pdf.next();
				pdf.style({fillcolor:"#FF0000",color:"0000FF"});//fill and change text color
				pdf.nline("this column will be filled in with color");
		pdf.end();
    


Page loading

Pages are added when needed and their pagenumber is added (see this.pagenumber.x , y for location)
	let pdf = new PDFColumns("filename");
	var test = await PDFLoadImage(pdf,'background',"back_image.png");
	pdf.pagecounter.y-=10; // can fix x and y to appropriate location
	pdf.dim.left+=5;
	pdf.dim.bottom+=5;
	pdf.newPage();
	pdf.col(2);
		for(let c = 0;c<2;c++){
			for(let i = 0;i<200;i++)
				pdf.nline("This is column "+(c+1)+" and line "+i);
			pdf.next();
		}
	pdf.end();
	pdf.save();
	

Building tables

Here are a few examples where we build tables for objects and object arrays
	function example7generator(pdf, data){
	
	pdf.col(1);//wrapper
		pdf.style("table");//creates full table border
		
		let keys =null;
		//passed array of objects
		if (Array.isArray(data)){
		
			//gather all keys from the objects within the data array
			keys = Object.keys(data[0]);
			let filter_keys =[];
			data.forEach(row => { //find kes that arent in current list then concat them
					filter_keys = new Set(keys);
					keys = keys.concat(Object.keys(row).filter(key => !filter_keys.has(key)));
 			});
			
		//passed single object	
		}else{
			keys = Object.keys(data);
		}
		
		pdf.col(keys.length);//print header for keys table
		keys.forEach(head => {pdf.style("tableheader");pdf.nline(head); pdf.next()});
		pdf.end();//end header
		for(let i = 0;i<(Array.isArray(data)?data.length:1);i++){
			pdf.col(keys.length);//by starting and ending columns each row we can have row borders,otherwise omit
			keys.forEach(head => {	pdf.style("tableline"+(i%2));
									pdf.nline((Array.isArray(data)?data[i][head]:data[head]));
									pdf.next();
									});
			pdf.end();
		}
	pdf.end();//wrapper
	}
	
	// start pdf and add some table styles that show borders and background-color (fillcolor)
	let pdf = new PDFColumns("filename");
    pdf.addStyle({name:"table",border:"#000000",font:"verdana"});
	pdf.addStyle({name:"tableheader",fillcolor:"#DDDDDD",fontstyle:"bold"});
	pdf.addStyle({name:"tableline0",fillcolor:"#ffffff",fontstyle:"normal"});
	pdf.addStyle({name:"tableline1",fillcolor:"#f4f4f4"});
	
	pdf.newPage(); //do variable loading as above
	
		// lets put a single object through a column generator
		let data = {name:"BMW #005", type:"car", cost:"$36,000", color:"black"};
		example7generator(pdf,data);
		pdf.nline();
		
		// Now lets make an array of objects to pass through
		// a column generator
		data= [{name:"horse",color:"brown",speed:"fastest",size:"huge"},
					{name:"dog",color:"white",speed:"fast",size:"big"},
					{name:"cat",color:"orange",speed:"meh",size:"small"},
					{name:"mouse",color:"grey",speed:"slight",size:"tiny"}];
		
		example7generator(pdf,data);//same as above
		pdf.nline();
		//simple generator for object arrays
		let keys =Object.keys(data[0]);
		pdf.col(1);//wrapper
			pdf.style("table");//creates full table border
			pdf.col(keys.length);//animal, size, color etc...
				//print header
				keys.forEach(head => {pdf.style("tableheader");pdf.nline(head); pdf.next()});
				//write rows
				for(let i = 0;i {	pdf.style("tableline"+(i%2));
											pdf.nline(data[i][head]);
											pdf.next()});
				}
			pdf.end();
		pdf.end();//wrapper*/
		pdf.nline();
		
		//Last lets fee some data from the styles we have given the PDFColumns pdf
		example7generator(pdf,pdf.styles);
		
	pdf.save();
	

Inserting Pictures

pictures loaded in can be placed on page with cimage and cbimage (which appends flag background to flags) Pictures can be back or inline with text, be given own size or "auto" to scale with column size
	let pdf = new PDFColumns("filename");
		await PDFLoadImage(pdf,'robocat',"doraemon.png");
	        
		// add a page with auto-numbering and background
		pdf.newPage();
		pdf.nline();
		pdf.col(3,[3,5,3]);
			pdf.next();
			pdf.style({border:"#FF0000"});
			pdf.cbimage('robocat');
			pdf.nline("This cat was a robot sent to the past to protect and teach an important scientist before he grows up; sent by the man himself from the future",{wrap:true, align:"center"});
		pdf.end();
		pdf.col(3);
			
			// fill with color and with background image
			pdf.style({fillcolor:"#FF0000"});
			pdf.cbimage('robocat');
			pdf.nline("write over",{align:"center"});
		pdf.next();
			
			//add border around, and image is inline with text
			pdf.style({border:"#00FF00"});
			pdf.cimage('robocat');
			pdf.nline("write under",{align:"center"});
		pdf.next();
			
			//image has been centered (point of drawing) with background color
			pdf.style({fillcolor:"#0000FF"});
			pdf.cimage('robocat',{height:40, alignx:"center", aligny:"center"});
			pdf.nline("write under");
		
		pdf.save();