pdfmake
Version:
Client/server side PDF printing in pure JavaScript
354 lines (350 loc) • 10.8 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _variableType = require("./helpers/variableType");
var _tools = require("./helpers/tools");
var _DocumentContext = _interopRequireDefault(require("./DocumentContext"));
var _events = require("events");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* A line/vector writer, which adds elements to current page and sets
* their positions based on the context
*/
class ElementWriter extends _events.EventEmitter {
/**
* @param {DocumentContext} context
*/
constructor(context) {
super();
this._context = context;
this.contextStack = [];
}
/**
* @returns {DocumentContext}
*/
context() {
return this._context;
}
addLine(line, dontUpdateContextPosition, index) {
let height = line.getHeight();
let context = this.context();
let page = context.getCurrentPage();
let position = this.getCurrentPositionOnPage();
if (context.availableHeight < height || !page) {
return false;
}
line.x = context.x + (line.x || 0);
line.y = context.y + (line.y || 0);
this.alignLine(line);
addPageItem(page, {
type: 'line',
item: line
}, index);
this.emit('lineAdded', line);
if (!dontUpdateContextPosition) {
context.moveDown(height);
}
return position;
}
alignLine(line) {
let width = this.context().availableWidth;
let lineWidth = line.getWidth();
let alignment = line.inlines && line.inlines.length > 0 && line.inlines[0].alignment;
let offset = 0;
switch (alignment) {
case 'right':
offset = width - lineWidth;
break;
case 'center':
offset = (width - lineWidth) / 2;
break;
}
if (offset) {
line.x = (line.x || 0) + offset;
}
if (alignment === 'justify' && !line.newLineForced && !line.lastLineInParagraph && line.inlines.length > 1) {
let additionalSpacing = (width - lineWidth) / (line.inlines.length - 1);
for (let i = 1, l = line.inlines.length; i < l; i++) {
offset = i * additionalSpacing;
line.inlines[i].x += offset;
line.inlines[i].justifyShift = additionalSpacing;
}
}
}
addImage(image, index) {
let context = this.context();
let page = context.getCurrentPage();
let position = this.getCurrentPositionOnPage();
if (!page || image.absolutePosition === undefined && context.availableHeight < image._height && page.items.length > 0) {
return false;
}
if (image._x === undefined) {
image._x = image.x || 0;
}
image.x = context.x + image._x;
image.y = context.y;
this.alignImage(image);
addPageItem(page, {
type: 'image',
item: image
}, index);
context.moveDown(image._height);
return position;
}
addCanvas(node, index) {
let context = this.context();
let page = context.getCurrentPage();
let positions = [];
let height = node._minHeight;
if (!page || node.absolutePosition === undefined && context.availableHeight < height) {
// TODO: support for canvas larger than a page
// TODO: support for other overflow methods
return false;
}
this.alignCanvas(node);
node.canvas.forEach(function (vector) {
let position = this.addVector(vector, false, false, index);
positions.push(position);
if (index !== undefined) {
index++;
}
}, this);
context.moveDown(height);
return positions;
}
addSVG(image, index) {
// TODO: same as addImage
let context = this.context();
let page = context.getCurrentPage();
let position = this.getCurrentPositionOnPage();
if (!page || image.absolutePosition === undefined && context.availableHeight < image._height && page.items.length > 0) {
return false;
}
if (image._x === undefined) {
image._x = image.x || 0;
}
image.x = context.x + image._x;
image.y = context.y;
this.alignImage(image);
addPageItem(page, {
type: 'svg',
item: image
}, index);
context.moveDown(image._height);
return position;
}
addQr(qr, index) {
let context = this.context();
let page = context.getCurrentPage();
let position = this.getCurrentPositionOnPage();
if (!page || qr.absolutePosition === undefined && context.availableHeight < qr._height) {
return false;
}
if (qr._x === undefined) {
qr._x = qr.x || 0;
}
qr.x = context.x + qr._x;
qr.y = context.y;
this.alignImage(qr);
for (let i = 0, l = qr._canvas.length; i < l; i++) {
let vector = qr._canvas[i];
vector.x += qr.x;
vector.y += qr.y;
this.addVector(vector, true, true, index);
}
context.moveDown(qr._height);
return position;
}
addAttachment(attachment, index) {
let context = this.context();
let page = context.getCurrentPage();
let position = this.getCurrentPositionOnPage();
if (!page || attachment.absolutePosition === undefined && context.availableHeight < attachment._height && page.items.length > 0) {
return false;
}
if (attachment._x === undefined) {
attachment._x = attachment.x || 0;
}
attachment.x = context.x + attachment._x;
attachment.y = context.y;
addPageItem(page, {
type: 'attachment',
item: attachment
}, index);
context.moveDown(attachment._height);
return position;
}
alignImage(image) {
let width = this.context().availableWidth;
let imageWidth = image._minWidth;
let offset = 0;
switch (image._alignment) {
case 'right':
offset = width - imageWidth;
break;
case 'center':
offset = (width - imageWidth) / 2;
break;
}
if (offset) {
image.x = (image.x || 0) + offset;
}
}
alignCanvas(node) {
let width = this.context().availableWidth;
let canvasWidth = node._minWidth;
let offset = 0;
switch (node._alignment) {
case 'right':
offset = width - canvasWidth;
break;
case 'center':
offset = (width - canvasWidth) / 2;
break;
}
if (offset) {
node.canvas.forEach(vector => {
(0, _tools.offsetVector)(vector, offset, 0);
});
}
}
addVector(vector, ignoreContextX, ignoreContextY, index, forcePage) {
let context = this.context();
let page = context.getCurrentPage();
if ((0, _variableType.isNumber)(forcePage)) {
page = context.pages[forcePage];
}
let position = this.getCurrentPositionOnPage();
if (page) {
(0, _tools.offsetVector)(vector, ignoreContextX ? 0 : context.x, ignoreContextY ? 0 : context.y);
addPageItem(page, {
type: 'vector',
item: vector
}, index);
return position;
}
}
beginClip(width, height) {
let ctx = this.context();
let page = ctx.getCurrentPage();
page.items.push({
type: 'beginClip',
item: {
x: ctx.x,
y: ctx.y,
width: width,
height: height
}
});
return true;
}
endClip() {
let ctx = this.context();
let page = ctx.getCurrentPage();
page.items.push({
type: 'endClip'
});
return true;
}
addFragment(block, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {
let ctx = this.context();
let page = ctx.getCurrentPage();
if (!useBlockXOffset && block.height > ctx.availableHeight) {
return false;
}
block.items.forEach(item => {
switch (item.type) {
case 'line':
var l = item.item.clone();
if (l._node) {
l._node.positions[0].pageNumber = ctx.page + 1;
}
l.x = (l.x || 0) + (useBlockXOffset ? block.xOffset || 0 : ctx.x);
l.y = (l.y || 0) + (useBlockYOffset ? block.yOffset || 0 : ctx.y);
page.items.push({
type: 'line',
item: l
});
break;
case 'vector':
var v = (0, _tools.pack)(item.item);
(0, _tools.offsetVector)(v, useBlockXOffset ? block.xOffset || 0 : ctx.x, useBlockYOffset ? block.yOffset || 0 : ctx.y);
if (v._isFillColorFromUnbreakable) {
// If the item is a fillColor from an unbreakable block
// We have to add it at the beginning of the items body array of the page
delete v._isFillColorFromUnbreakable;
const endOfBackgroundItemsIndex = ctx.backgroundLength[ctx.page];
page.items.splice(endOfBackgroundItemsIndex, 0, {
type: 'vector',
item: v
});
} else {
page.items.push({
type: 'vector',
item: v
});
}
break;
case 'image':
case 'svg':
var img = (0, _tools.pack)(item.item);
img.x = (img.x || 0) + (useBlockXOffset ? block.xOffset || 0 : ctx.x);
img.y = (img.y || 0) + (useBlockYOffset ? block.yOffset || 0 : ctx.y);
page.items.push({
type: item.type,
item: img
});
break;
}
});
if (!dontUpdateContextPosition) {
ctx.moveDown(block.height);
}
return true;
}
/**
* Pushes the provided context onto the stack or creates a new one
*
* pushContext(context) - pushes the provided context and makes it current
* 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 {DocumentContext|number} contextOrWidth
* @param {number} height
*/
pushContext(contextOrWidth, height) {
if (contextOrWidth === undefined) {
height = this.context().getCurrentPage().height - this.context().pageMargins.top - this.context().pageMargins.bottom;
contextOrWidth = this.context().availableWidth;
}
if ((0, _variableType.isNumber)(contextOrWidth)) {
let width = contextOrWidth;
contextOrWidth = new _DocumentContext.default();
contextOrWidth.addPage({
width: width,
height: height
}, {
left: 0,
right: 0,
top: 0,
bottom: 0
});
}
this.contextStack.push(this.context());
this._context = contextOrWidth;
}
popContext() {
this._context = this.contextStack.pop();
}
getCurrentPositionOnPage() {
return (this.contextStack[0] || this.context()).getCurrentPosition();
}
}
function addPageItem(page, item, index) {
if (index === null || index === undefined || index < 0 || index > page.items.length) {
page.items.push(item);
} else {
page.items.splice(index, 0, item);
}
}
var _default = exports.default = ElementWriter;