Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] New section node #1972

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2d44e3b
start of implementing node section
liborm85 Mar 23, 2020
0e784b0
fixed wrapping section to new page
liborm85 Mar 23, 2020
4c60f75
refactor normalize page size and page margin
liborm85 Apr 26, 2020
551f518
support for different page sizes in sections
liborm85 Apr 28, 2020
dd901dd
add simple example
liborm85 Apr 29, 2020
4af6633
support pageMargins
liborm85 Apr 29, 2020
eae343b
fix set section page margin
liborm85 Apr 29, 2020
46ce02d
fix loading default pagesize and pagemargins
liborm85 Jun 14, 2020
b03372b
Merge branch 'master' into features/node-section
liborm85 Jul 10, 2020
bb89d18
fix formating
liborm85 Jul 10, 2020
a1d50cf
Merge branch 'master' into features/node-section
liborm85 Aug 23, 2020
5b728c3
update example by new interface
liborm85 Aug 23, 2020
ba935c2
Merge branch 'master' into features/node-section
liborm85 Dec 28, 2020
9ca2323
Merge branch 'master' into features/node-section
liborm85 Jul 6, 2021
d9bade3
Merge branch 'master' into features/node-section
liborm85 Nov 6, 2021
970773f
Merge branch 'master' into features/node-section
liborm85 Jan 1, 2022
122fb03
Merge branch 'master' into features/node-section
liborm85 Jan 8, 2022
befd38a
fix example
liborm85 Jan 8, 2022
dc76a77
fix header/footer in sections with pagemargins
liborm85 Jan 8, 2022
f00a33f
fix render wrong first page size
liborm85 Jan 9, 2022
a516fb9
fix tests
liborm85 Jan 9, 2022
04e942c
add docs
liborm85 Jan 15, 2022
ff321c7
fix
liborm85 Jan 15, 2022
fcb1001
fix inserting section first page
liborm85 Jan 29, 2022
19e5d1e
fix test first page initialization
liborm85 Jan 29, 2022
f694c35
remove dead code
liborm85 Jan 29, 2022
993daa7
refactoring header/footer conversion
liborm85 Jan 30, 2022
5680673
Merge branch 'master' into features/node-section
liborm85 Apr 2, 2022
7609b92
Merge branch 'master' into features/node-section
liborm85 Dec 18, 2022
656d24c
Merge branch 'master' into features/node-section
liborm85 Dec 21, 2023
814c032
Merge branch 'master' into features/node-section
liborm85 Jan 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added examples/pdfs/sections.pdf
Binary file not shown.
58 changes: 58 additions & 0 deletions examples/sections.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
var pdfmake = require('../js/index'); // only during development, otherwise use the following line
//var pdfmake = require('pdfmake');

var Roboto = require('../fonts/Roboto');
pdfmake.addFonts(Roboto);

var docDefinition = {
content: [
{
section: [
'SECTION 1',
'Text in section.'
]
},
{
pageOrientation: 'landscape',
section: [
'SECTION 2',
'Text in section as landscape page.'
]
},
{
pageSize: 'A7',
pageOrientation: 'portrait',
section: [
'SECTION 3',
'Text in section as A7 page.'
]
},
{
pageSize: 'A6',
pageOrientation: 'portrait',
pageMargins: 5,
section: [
'SECTION 4',
'Text in section as A6 page with margin.'
]
},
{
pageSize: 'A6',
pageOrientation: 'landscape',
pageMargins: 5,
section: [
'SECTION 5',
'Text in section as A6 landscape page with margin.'
]
}
]
};

var now = new Date();

var pdf = pdfmake.createPdf(docDefinition);
pdf.write('pdfs/sections.pdf').then(() => {
console.log(new Date() - now);
}, err => {
console.error(err);
});
12 changes: 11 additions & 1 deletion src/DocMeasure.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ class DocMeasure {
// TODO: refactor + rethink whether this is the proper way to handle margins
node._margin = getNodeMargin(node, this.styleStack);

if (node.columns) {
if (node.section) {
return extendMargins(this.measureSection(node));
} else if (node.columns) {
return extendMargins(this.measureColumns(node));
} else if (node.stack) {
return extendMargins(this.measureVerticalContainer(node));
Expand Down Expand Up @@ -458,6 +460,14 @@ class DocMeasure {
return node;
}

measureSection(node) {
// TODO: properties

node.section = this.measureNode(node.section);

return node;
}

measureColumns(node) {
let columns = node.columns;
node._gap = this.styleStack.getProperty('columnGap') || 0;
Expand Down
10 changes: 9 additions & 1 deletion src/DocPreprocessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class DocPreprocessor {
node.text = convertValueToString(node.text);
}

if (node.columns) {
if (node.section) {
return this.preprocessSection(node);
} else if (node.columns) {
return this.preprocessColumns(node);
} else if (node.stack) {
return this.preprocessVerticalContainer(node);
Expand Down Expand Up @@ -64,6 +66,12 @@ class DocPreprocessor {
}
}

preprocessSection(node) {
node.section = this.preprocessNode(node.section);

return node;
}

preprocessColumns(node) {
let columns = node.columns;

Expand Down
20 changes: 9 additions & 11 deletions src/DocumentContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,14 @@ import { EventEmitter } from 'events';
* It facilitates column divisions and vertical sync
*/
class DocumentContext extends EventEmitter {
constructor(pageSize, pageMargins) {
constructor() {
super();
this.pages = [];

this.pageMargins = pageMargins;

this.x = pageMargins.left;
this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;
this.availableHeight = 0;
this.page = -1;

this.snapshots = [];
this.endingCell = null;
this.backgroundLength = [];

this.addPage(pageSize);
}

beginColumnGroup() {
Expand Down Expand Up @@ -217,8 +209,14 @@ class DocumentContext extends EventEmitter {
};
}

addPage(pageSize) {
let page = { items: [], pageSize: pageSize };
addPage(pageSize, pageMargin = null) {
if (pageMargin !== null) {
this.pageMargins = pageMargin;
this.x = pageMargin.left;
this.availableWidth = pageSize.width - pageMargin.left - pageMargin.right;
}

let page = { items: [], pageSize: pageSize, pageMargins: this.pageMargins };
this.pages.push(page);
this.backgroundLength.push(0);
this.page = this.pages.length - 1;
Expand Down
13 changes: 11 additions & 2 deletions src/ElementWriter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ import { EventEmitter } from 'events';
* their positions based on the context
*/
class ElementWriter extends EventEmitter {

/**
* @param {DocumentContext} context
*/
constructor(context) {
super();
this._context = context;
this.contextStack = [];
}

/**
* @returns {DocumentContext}
*/
context() {
return this._context;
}
Expand Down Expand Up @@ -357,7 +364,7 @@ class ElementWriter extends EventEmitter {
* pushContext(width, height) - creates and pushes a new context with the specified width and height
* pushContext() - creates a new context for unbreakable blocks (with current availableWidth and full-page-height)
*
* @param {object|number} contextOrWidth
* @param {DocumentContext|number} contextOrWidth
* @param {number} height
*/
pushContext(contextOrWidth, height) {
Expand All @@ -367,7 +374,9 @@ class ElementWriter extends EventEmitter {
}

if (isNumber(contextOrWidth)) {
contextOrWidth = new DocumentContext({ width: contextOrWidth, height: height }, { left: 0, right: 0, top: 0, bottom: 0 });
let width = contextOrWidth;
contextOrWidth = new DocumentContext();
contextOrWidth.addPage({ width: width, height: height }, { left: 0, right: 0, top: 0, bottom: 0 });
}

this.contextStack.push(this.context());
Expand Down
57 changes: 42 additions & 15 deletions src/LayoutBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,18 +167,34 @@ class LayoutBuilder {
watermark
) {

const isNecessaryAddFirstPage = (docStructure) => {
if (docStructure.stack && docStructure.stack.length > 0 && docStructure.stack[0].section) {
return false;
} else if (docStructure.section) {
return false;
}

return true;
};

this.linearNodeList = [];
docStructure = this.docPreprocessor.preprocessDocument(docStructure);
docStructure = this.docMeasure.measureDocument(docStructure);

this.writer = new PageElementWriter(
new DocumentContext(this.pageSize, this.pageMargins));
this.writer = new PageElementWriter(new DocumentContext());

this.writer.context().addListener('pageAdded', () => {
this.addBackground(background);
});

this.addBackground(background);
if (isNecessaryAddFirstPage(docStructure)) {
this.writer.addPage(
this.pageSize,
null,
this.pageMargins
);
}

this.processNode(docStructure);
this.addHeadersAndFooters(header, footer);
if (watermark != null) {
Expand All @@ -205,11 +221,6 @@ class LayoutBuilder {
}
}

addStaticRepeatable(headerOrFooter, sizeFunction) {
this.addDynamicRepeatable(() => // copy to new object
JSON.parse(JSON.stringify(headerOrFooter)), sizeFunction);
}

addDynamicRepeatable(nodeGetter, sizeFunction) {
let pages = this.writer.context().pages;

Expand All @@ -219,7 +230,7 @@ class LayoutBuilder {
let node = nodeGetter(pageIndex + 1, l, this.writer.context().pages[pageIndex].pageSize);

if (node) {
let sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.pageMargins);
let sizes = sizeFunction(this.writer.context().getCurrentPage().pageSize, this.writer.context().getCurrentPage().pageMargins);
this.writer.beginUnbreakableBlock(sizes.width, sizes.height);
node = this.docPreprocessor.preprocessDocument(node);
this.processNode(this.docMeasure.measureDocument(node));
Expand All @@ -243,16 +254,12 @@ class LayoutBuilder {
height: pageMargins.bottom
});

if (typeof header === 'function') {
if (header) {
this.addDynamicRepeatable(header, headerSizeFct);
} else if (header) {
this.addStaticRepeatable(header, headerSizeFct);
}

if (typeof footer === 'function') {
if (footer) {
this.addDynamicRepeatable(footer, footerSizeFct);
} else if (footer) {
this.addStaticRepeatable(footer, footerSizeFct);
}
}

Expand Down Expand Up @@ -419,6 +426,8 @@ class LayoutBuilder {

if (node.stack) {
this.processVerticalContainer(node);
} else if (node.section) {
this.processSection(node);
} else if (node.columns) {
this.processColumns(node);
} else if (node.ul) {
Expand Down Expand Up @@ -465,6 +474,24 @@ class LayoutBuilder {
}, this);
}

// section
processSection(sectionNode) {
// TODO: properties

let page = this.writer.context().getCurrentPage();
// TODO: background
if (!page || (page && page.items.length)) { // move to new empty page
// TODO: property for inherit page size and margin from before section
this.writer.addPage(
sectionNode.pageSize || this.pageSize,
sectionNode.pageOrientation,
sectionNode.pageMargins || this.pageMargins
);
}

this.processNode(sectionNode.section);
}

// columns
processColumns(columnNode) {
let columns = columnNode.columns;
Expand Down
19 changes: 19 additions & 0 deletions src/PageElementWriter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import ElementWriter from './ElementWriter';
import { normalizePageSize, normalizePageMargin } from './PageSize';
import DocumentContext from './DocumentContext';

/**
* An extended ElementWriter which can handle:
Expand All @@ -9,6 +11,10 @@ import ElementWriter from './ElementWriter';
* whole block will be rendered on the same page)
*/
class PageElementWriter extends ElementWriter {

/**
* @param {DocumentContext} context
*/
constructor(context) {
super(context);
this.transactionLevel = 0;
Expand Down Expand Up @@ -77,6 +83,19 @@ class PageElementWriter extends ElementWriter {
});
}

addPage(pageSize, pageOrientation, pageMargin) {
let prevPage = this.page;
let prevY = this.y;

this.context().addPage(normalizePageSize(pageSize, pageOrientation), normalizePageMargin(pageMargin));

this.emit('pageChanged', {
prevPage: prevPage,
prevY: prevY,
y: this.context().y
});
}

beginUnbreakableBlock(width, height) {
if (this.transactionLevel++ === 0) {
this.originalX = this.context().x;
Expand Down
9 changes: 9 additions & 0 deletions src/Printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { normalizePageSize, normalizePageMargin } from './PageSize';
import { tableLayouts } from './tableLayouts';
import Renderer from './Renderer';
import { isNumber, isValue } from './helpers/variableType';
import { convertToDynamicContent } from './helpers/tools';

/**
* Printer which turns document definition into a pdf
Expand Down Expand Up @@ -53,6 +54,14 @@ class PdfPrinter {
docDefinition.pageMargins = isValue(docDefinition.pageMargins) ? docDefinition.pageMargins : 40;
docDefinition.patterns = docDefinition.patterns || {};

if (docDefinition.header && typeof docDefinition.header !== 'function') {
docDefinition.header = convertToDynamicContent(docDefinition.header);
}

if (docDefinition.footer && typeof docDefinition.footer !== 'function') {
docDefinition.footer = convertToDynamicContent(docDefinition.footer);
}

let pageSize = normalizePageSize(docDefinition.pageSize, docDefinition.pageOrientation);

let pdfOptions = {
Expand Down
15 changes: 1 addition & 14 deletions src/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class Renderer {

renderPages(pages) {
this.pdfDocument._pdfMakePages = pages; // TODO: Why?
this.pdfDocument.addPage();

let totalItems = 0;
if (this.progressCallback) {
Expand All @@ -57,10 +56,7 @@ class Renderer {
let renderedItems = 0;

for (let i = 0; i < pages.length; i++) {
if (i > 0) {
this._updatePageOrientationInOptions(pages[i]);
this.pdfDocument.addPage(this.pdfDocument.options);
}
this.pdfDocument.addPage({size: [pages[i].pageSize.width, pages[i].pageSize.height]});

let page = pages[i];
for (let ii = 0, il = page.items.length; ii < il; ii++) {
Expand Down Expand Up @@ -391,15 +387,6 @@ class Renderer {
this.pdfDocument.restore();
}

_updatePageOrientationInOptions(currentPage) {
let previousPageOrientation = this.pdfDocument.options.size[0] > this.pdfDocument.options.size[1] ? 'landscape' : 'portrait';

if (currentPage.pageSize.orientation !== previousPageOrientation) {
let width = this.pdfDocument.options.size[0];
let height = this.pdfDocument.options.size[1];
this.pdfDocument.options.size = [height, width];
}
}
}

export default Renderer;
Loading
Loading