UNPKG

pdfmake

Version:

Client/server side PDF printing in pure JavaScript

315 lines (257 loc) 8.4 kB
'use strict'; var TraversalTracker = require('./traversalTracker'); var isString = require('./helpers').isString; /** * Creates an instance of DocumentContext - a store for current x, y positions and available width/height. * It facilitates column divisions and vertical sync */ function DocumentContext(pageSize, pageMargins) { 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.tracker = new TraversalTracker(); this.backgroundLength = []; this.addPage(pageSize); } DocumentContext.prototype.beginColumnGroup = function () { this.snapshots.push({ x: this.x, y: this.y, availableHeight: this.availableHeight, availableWidth: this.availableWidth, page: this.page, bottomMost: { x: this.x, y: this.y, availableHeight: this.availableHeight, availableWidth: this.availableWidth, page: this.page }, endingCell: this.endingCell, lastColumnWidth: this.lastColumnWidth }); this.lastColumnWidth = 0; }; DocumentContext.prototype.beginColumn = function (width, offset, endingCell) { var saved = this.snapshots[this.snapshots.length - 1]; this.calculateBottomMost(saved); this.endingCell = endingCell; this.page = saved.page; this.x = this.x + this.lastColumnWidth + (offset || 0); this.y = saved.y; this.availableWidth = width; //saved.availableWidth - offset; this.availableHeight = saved.availableHeight; this.lastColumnWidth = width; }; DocumentContext.prototype.calculateBottomMost = function (destContext) { if (this.endingCell) { this.saveContextInEndingCell(this.endingCell); this.endingCell = null; } else { destContext.bottomMost = bottomMostContext(this, destContext.bottomMost); } }; DocumentContext.prototype.markEnding = function (endingCell) { this.page = endingCell._columnEndingContext.page; this.x = endingCell._columnEndingContext.x; this.y = endingCell._columnEndingContext.y; this.availableWidth = endingCell._columnEndingContext.availableWidth; this.availableHeight = endingCell._columnEndingContext.availableHeight; this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth; }; DocumentContext.prototype.saveContextInEndingCell = function (endingCell) { endingCell._columnEndingContext = { page: this.page, x: this.x, y: this.y, availableHeight: this.availableHeight, availableWidth: this.availableWidth, lastColumnWidth: this.lastColumnWidth }; }; DocumentContext.prototype.completeColumnGroup = function (height) { var saved = this.snapshots.pop(); this.calculateBottomMost(saved); this.endingCell = null; this.x = saved.x; var y = saved.bottomMost.y; if (height) { if (saved.page === saved.bottomMost.page) { if ((saved.y + height) > y) { y = saved.y + height; } } else { y += height; } } this.y = y; this.page = saved.bottomMost.page; this.availableWidth = saved.availableWidth; this.availableHeight = saved.bottomMost.availableHeight; if (height) { this.availableHeight -= (y - saved.bottomMost.y); } this.lastColumnWidth = saved.lastColumnWidth; }; DocumentContext.prototype.addMargin = function (left, right) { this.x += left; this.availableWidth -= left + (right || 0); }; DocumentContext.prototype.moveDown = function (offset) { this.y += offset; this.availableHeight -= offset; return this.availableHeight > 0; }; DocumentContext.prototype.initializePage = function () { this.y = this.pageMargins.top; this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom; this.pageSnapshot().availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right; }; DocumentContext.prototype.pageSnapshot = function () { if (this.snapshots[0]) { return this.snapshots[0]; } else { return this; } }; DocumentContext.prototype.moveTo = function (x, y) { if (x !== undefined && x !== null) { this.x = x; this.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right; } if (y !== undefined && y !== null) { this.y = y; this.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom; } }; DocumentContext.prototype.moveToRelative = function (x, y) { if (x !== undefined && x !== null) { this.x = this.x + x; } if (y !== undefined && y !== null) { this.y = this.y + y; } }; DocumentContext.prototype.beginDetachedBlock = function () { this.snapshots.push({ x: this.x, y: this.y, availableHeight: this.availableHeight, availableWidth: this.availableWidth, page: this.page, endingCell: this.endingCell, lastColumnWidth: this.lastColumnWidth }); }; DocumentContext.prototype.endDetachedBlock = function () { var saved = this.snapshots.pop(); this.x = saved.x; this.y = saved.y; this.availableWidth = saved.availableWidth; this.availableHeight = saved.availableHeight; this.page = saved.page; this.endingCell = saved.endingCell; this.lastColumnWidth = saved.lastColumnWidth; }; function pageOrientation(pageOrientationString, currentPageOrientation) { if (pageOrientationString === undefined) { return currentPageOrientation; } else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) { return 'landscape'; } else { return 'portrait'; } } var getPageSize = function (currentPage, newPageOrientation) { newPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation); if (newPageOrientation !== currentPage.pageSize.orientation) { return { orientation: newPageOrientation, width: currentPage.pageSize.height, height: currentPage.pageSize.width }; } else { return { orientation: currentPage.pageSize.orientation, width: currentPage.pageSize.width, height: currentPage.pageSize.height }; } }; DocumentContext.prototype.moveToNextPage = function (pageOrientation) { var nextPageIndex = this.page + 1; var prevPage = this.page; var prevY = this.y; var createNewPage = nextPageIndex >= this.pages.length; if (createNewPage) { var currentAvailableWidth = this.availableWidth; var currentPageOrientation = this.getCurrentPage().pageSize.orientation; var pageSize = getPageSize(this.getCurrentPage(), pageOrientation); this.addPage(pageSize); if (currentPageOrientation === pageSize.orientation) { this.availableWidth = currentAvailableWidth; } } else { this.page = nextPageIndex; this.initializePage(); } return { newPageCreated: createNewPage, prevPage: prevPage, prevY: prevY, y: this.y }; }; DocumentContext.prototype.addPage = function (pageSize) { var page = { items: [], pageSize: pageSize }; this.pages.push(page); this.backgroundLength.push(0); this.page = this.pages.length - 1; this.initializePage(); this.tracker.emit('pageAdded'); return page; }; DocumentContext.prototype.getCurrentPage = function () { if (this.page < 0 || this.page >= this.pages.length) { return null; } return this.pages[this.page]; }; DocumentContext.prototype.getCurrentPosition = function () { var pageSize = this.getCurrentPage().pageSize; var innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom; var innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right; return { pageNumber: this.page + 1, pageOrientation: pageSize.orientation, pageInnerHeight: innerHeight, pageInnerWidth: innerWidth, left: this.x, top: this.y, verticalRatio: ((this.y - this.pageMargins.top) / innerHeight), horizontalRatio: ((this.x - this.pageMargins.left) / innerWidth) }; }; function bottomMostContext(c1, c2) { var r; if (c1.page > c2.page) { r = c1; } else if (c2.page > c1.page) { r = c2; } else { r = (c1.y > c2.y) ? c1 : c2; } return { page: r.page, x: r.x, y: r.y, availableHeight: r.availableHeight, availableWidth: r.availableWidth }; } module.exports = DocumentContext;