You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
807 lines
22 KiB
807 lines
22 KiB
/*eslint no-unused-vars: ["error", {"args": "none"}]*/
|
|
|
|
'use strict';
|
|
|
|
var TextTools = require('./textTools');
|
|
var StyleContextStack = require('./styleContextStack');
|
|
var ColumnCalculator = require('./columnCalculator');
|
|
var isString = require('./helpers').isString;
|
|
var isNumber = require('./helpers').isNumber;
|
|
var isObject = require('./helpers').isObject;
|
|
var isArray = require('./helpers').isArray;
|
|
var fontStringify = require('./helpers').fontStringify;
|
|
var getNodeId = require('./helpers').getNodeId;
|
|
var pack = require('./helpers').pack;
|
|
var qrEncoder = require('./qrEnc.js');
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
function DocMeasure(fontProvider, styleDictionary, defaultStyle, imageMeasure, svgMeasure, tableLayouts, images) {
|
|
this.textTools = new TextTools(fontProvider);
|
|
this.styleStack = new StyleContextStack(styleDictionary, defaultStyle);
|
|
this.imageMeasure = imageMeasure;
|
|
this.svgMeasure = svgMeasure;
|
|
this.tableLayouts = tableLayouts;
|
|
this.images = images;
|
|
this.autoImageIndex = 1;
|
|
}
|
|
|
|
/**
|
|
* Measures all nodes and sets min/max-width properties required for the second
|
|
* layout-pass.
|
|
* @param {Object} docStructure document-definition-object
|
|
* @return {Object} document-measurement-object
|
|
*/
|
|
DocMeasure.prototype.measureDocument = function (docStructure) {
|
|
return this.measureNode(docStructure);
|
|
};
|
|
|
|
DocMeasure.prototype.measureNode = function (node) {
|
|
|
|
var self = this;
|
|
|
|
return this.styleStack.auto(node, function () {
|
|
// TODO: refactor + rethink whether this is the proper way to handle margins
|
|
node._margin = getNodeMargin(node);
|
|
|
|
if (node.columns) {
|
|
return extendMargins(self.measureColumns(node));
|
|
} else if (node.stack) {
|
|
return extendMargins(self.measureVerticalContainer(node));
|
|
} else if (node.ul) {
|
|
return extendMargins(self.measureUnorderedList(node));
|
|
} else if (node.ol) {
|
|
return extendMargins(self.measureOrderedList(node));
|
|
} else if (node.table) {
|
|
return extendMargins(self.measureTable(node));
|
|
} else if (node.text !== undefined) {
|
|
return extendMargins(self.measureLeaf(node));
|
|
} else if (node.toc) {
|
|
return extendMargins(self.measureToc(node));
|
|
} else if (node.image) {
|
|
return extendMargins(self.measureImage(node));
|
|
} else if (node.svg) {
|
|
return extendMargins(self.measureSVG(node));
|
|
} else if (node.canvas) {
|
|
return extendMargins(self.measureCanvas(node));
|
|
} else if (node.qr) {
|
|
return extendMargins(self.measureQr(node));
|
|
} else {
|
|
throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);
|
|
}
|
|
});
|
|
|
|
function extendMargins(node) {
|
|
var margin = node._margin;
|
|
|
|
if (margin) {
|
|
node._minWidth += margin[0] + margin[2];
|
|
node._maxWidth += margin[0] + margin[2];
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
function getNodeMargin() {
|
|
|
|
function processSingleMargins(node, currentMargin) {
|
|
if (node.marginLeft || node.marginTop || node.marginRight || node.marginBottom) {
|
|
return [
|
|
node.marginLeft || currentMargin[0] || 0,
|
|
node.marginTop || currentMargin[1] || 0,
|
|
node.marginRight || currentMargin[2] || 0,
|
|
node.marginBottom || currentMargin[3] || 0
|
|
];
|
|
}
|
|
return currentMargin;
|
|
}
|
|
|
|
function flattenStyleArray(styleArray) {
|
|
var flattenedStyles = {};
|
|
for (var i = styleArray.length - 1; i >= 0; i--) {
|
|
var styleName = styleArray[i];
|
|
var style = self.styleStack.styleDictionary[styleName];
|
|
for (var key in style) {
|
|
if (style.hasOwnProperty(key)) {
|
|
flattenedStyles[key] = style[key];
|
|
}
|
|
}
|
|
}
|
|
return flattenedStyles;
|
|
}
|
|
|
|
function convertMargin(margin) {
|
|
if (isNumber(margin)) {
|
|
margin = [margin, margin, margin, margin];
|
|
} else if (isArray(margin)) {
|
|
if (margin.length === 2) {
|
|
margin = [margin[0], margin[1], margin[0], margin[1]];
|
|
}
|
|
}
|
|
return margin;
|
|
}
|
|
|
|
var margin = [undefined, undefined, undefined, undefined];
|
|
|
|
if (node.style) {
|
|
var styleArray = isArray(node.style) ? node.style : [node.style];
|
|
var flattenedStyleArray = flattenStyleArray(styleArray);
|
|
|
|
if (flattenedStyleArray) {
|
|
margin = processSingleMargins(flattenedStyleArray, margin);
|
|
}
|
|
|
|
if (flattenedStyleArray.margin) {
|
|
margin = convertMargin(flattenedStyleArray.margin);
|
|
}
|
|
}
|
|
|
|
margin = processSingleMargins(node, margin);
|
|
|
|
if (node.margin) {
|
|
margin = convertMargin(node.margin);
|
|
}
|
|
|
|
if (margin[0] === undefined && margin[1] === undefined && margin[2] === undefined && margin[3] === undefined) {
|
|
return null;
|
|
} else {
|
|
return margin;
|
|
}
|
|
}
|
|
};
|
|
|
|
DocMeasure.prototype.convertIfBase64Image = function (node) {
|
|
if (/^data:image\/(jpeg|jpg|png);base64,/.test(node.image)) {
|
|
var label = '$$pdfmake$$' + this.autoImageIndex++;
|
|
this.images[label] = node.image;
|
|
node.image = label;
|
|
}
|
|
};
|
|
|
|
DocMeasure.prototype.measureImageWithDimensions = function (node, dimensions) {
|
|
if (node.fit) {
|
|
var factor = (dimensions.width / dimensions.height > node.fit[0] / node.fit[1]) ? node.fit[0] / dimensions.width : node.fit[1] / dimensions.height;
|
|
node._width = node._minWidth = node._maxWidth = dimensions.width * factor;
|
|
node._height = dimensions.height * factor;
|
|
} else {
|
|
node._width = node._minWidth = node._maxWidth = node.width || dimensions.width;
|
|
node._height = node.height || (dimensions.height * node._width / dimensions.width);
|
|
|
|
if (isNumber(node.maxWidth) && node.maxWidth < node._width) {
|
|
node._width = node._minWidth = node._maxWidth = node.maxWidth;
|
|
node._height = node._width * dimensions.height / dimensions.width;
|
|
}
|
|
|
|
if (isNumber(node.maxHeight) && node.maxHeight < node._height) {
|
|
node._height = node.maxHeight;
|
|
node._width = node._minWidth = node._maxWidth = node._height * dimensions.width / dimensions.height;
|
|
}
|
|
|
|
if (isNumber(node.minWidth) && node.minWidth > node._width) {
|
|
node._width = node._minWidth = node._maxWidth = node.minWidth;
|
|
node._height = node._width * dimensions.height / dimensions.width;
|
|
}
|
|
|
|
if (isNumber(node.minHeight) && node.minHeight > node._height) {
|
|
node._height = node.minHeight;
|
|
node._width = node._minWidth = node._maxWidth = node._height * dimensions.width / dimensions.height;
|
|
}
|
|
}
|
|
|
|
node._alignment = this.styleStack.getProperty('alignment');
|
|
};
|
|
|
|
DocMeasure.prototype.measureImage = function (node) {
|
|
if (this.images) {
|
|
this.convertIfBase64Image(node);
|
|
}
|
|
|
|
var dimensions = this.imageMeasure.measureImage(node.image);
|
|
|
|
this.measureImageWithDimensions(node, dimensions);
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureSVG = function (node) {
|
|
|
|
var dimensions = this.svgMeasure.measureSVG(node.svg);
|
|
|
|
this.measureImageWithDimensions(node, dimensions);
|
|
|
|
node.font = this.styleStack.getProperty('font');
|
|
|
|
// scale SVG based on final dimension
|
|
node.svg = this.svgMeasure.writeDimensions(node.svg, {
|
|
width: node._width,
|
|
height: node._height
|
|
});
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureLeaf = function (node) {
|
|
|
|
if (node._textRef && node._textRef._textNodeRef.text) {
|
|
node.text = node._textRef._textNodeRef.text;
|
|
}
|
|
|
|
// Make sure style properties of the node itself are considered when building inlines.
|
|
// We could also just pass [node] to buildInlines, but that fails for bullet points.
|
|
var styleStack = this.styleStack.clone();
|
|
styleStack.push(node);
|
|
|
|
var data = this.textTools.buildInlines(node.text, styleStack);
|
|
|
|
node._inlines = data.items;
|
|
node._minWidth = data.minWidth;
|
|
node._maxWidth = data.maxWidth;
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureToc = function (node) {
|
|
if (node.toc.title) {
|
|
node.toc.title = this.measureNode(node.toc.title);
|
|
}
|
|
|
|
if (node.toc._items.length > 0) {
|
|
var body = [];
|
|
var textStyle = node.toc.textStyle || {};
|
|
var numberStyle = node.toc.numberStyle || textStyle;
|
|
var textMargin = node.toc.textMargin || [0, 0, 0, 0];
|
|
for (var i = 0, l = node.toc._items.length; i < l; i++) {
|
|
var item = node.toc._items[i];
|
|
var lineStyle = item._textNodeRef.tocStyle || textStyle;
|
|
var lineMargin = item._textNodeRef.tocMargin || textMargin;
|
|
var lineNumberStyle = item._textNodeRef.tocNumberStyle || numberStyle;
|
|
var destination = getNodeId(item._nodeRef);
|
|
body.push([
|
|
{ text: item._textNodeRef.text, linkToDestination: destination, alignment: 'left', style: lineStyle, margin: lineMargin },
|
|
{ text: '00000', linkToDestination: destination, alignment: 'right', _tocItemRef: item._nodeRef, style: lineNumberStyle, margin: [0, lineMargin[1], 0, lineMargin[3]] }
|
|
]);
|
|
}
|
|
|
|
|
|
node.toc._table = {
|
|
table: {
|
|
dontBreakRows: true,
|
|
widths: ['*', 'auto'],
|
|
body: body
|
|
},
|
|
layout: 'noBorders'
|
|
};
|
|
|
|
node.toc._table = this.measureNode(node.toc._table);
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureVerticalContainer = function (node) {
|
|
var items = node.stack;
|
|
|
|
node._minWidth = 0;
|
|
node._maxWidth = 0;
|
|
|
|
for (var i = 0, l = items.length; i < l; i++) {
|
|
items[i] = this.measureNode(items[i]);
|
|
|
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth);
|
|
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.gapSizeForList = function () {
|
|
return this.textTools.sizeOfString('9. ', this.styleStack);
|
|
};
|
|
|
|
DocMeasure.prototype.buildUnorderedMarker = function (styleStack, gapSize, type) {
|
|
function buildDisc(gapSize, color) {
|
|
// TODO: ascender-based calculations
|
|
var radius = gapSize.fontSize / 6;
|
|
return {
|
|
canvas: [{
|
|
x: radius,
|
|
y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,
|
|
r1: radius,
|
|
r2: radius,
|
|
type: 'ellipse',
|
|
color: color
|
|
}]
|
|
};
|
|
}
|
|
|
|
function buildSquare(gapSize, color) {
|
|
// TODO: ascender-based calculations
|
|
var size = gapSize.fontSize / 3;
|
|
return {
|
|
canvas: [{
|
|
x: 0,
|
|
y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - (gapSize.fontSize / 3) - (size / 2),
|
|
h: size,
|
|
w: size,
|
|
type: 'rect',
|
|
color: color
|
|
}]
|
|
};
|
|
}
|
|
|
|
function buildCircle(gapSize, color) {
|
|
// TODO: ascender-based calculations
|
|
var radius = gapSize.fontSize / 6;
|
|
return {
|
|
canvas: [{
|
|
x: radius,
|
|
y: (gapSize.height / gapSize.lineHeight) + gapSize.descender - gapSize.fontSize / 3,
|
|
r1: radius,
|
|
r2: radius,
|
|
type: 'ellipse',
|
|
lineColor: color
|
|
}]
|
|
};
|
|
}
|
|
|
|
var marker;
|
|
var color = styleStack.getProperty('markerColor') || styleStack.getProperty('color') || 'black';
|
|
|
|
switch (type) {
|
|
case 'circle':
|
|
marker = buildCircle(gapSize, color);
|
|
break;
|
|
|
|
case 'square':
|
|
marker = buildSquare(gapSize, color);
|
|
break;
|
|
|
|
case 'none':
|
|
marker = {};
|
|
break;
|
|
|
|
case 'disc':
|
|
default:
|
|
marker = buildDisc(gapSize, color);
|
|
break;
|
|
}
|
|
|
|
marker._minWidth = marker._maxWidth = gapSize.width;
|
|
marker._minHeight = marker._maxHeight = gapSize.height;
|
|
|
|
return marker;
|
|
};
|
|
|
|
DocMeasure.prototype.buildOrderedMarker = function (counter, styleStack, type, separator) {
|
|
function prepareAlpha(counter) {
|
|
function toAlpha(num) {
|
|
return (num >= 26 ? toAlpha((num / 26 >> 0) - 1) : '') + 'abcdefghijklmnopqrstuvwxyz'[num % 26 >> 0];
|
|
}
|
|
|
|
if (counter < 1) {
|
|
return counter.toString();
|
|
}
|
|
|
|
return toAlpha(counter - 1);
|
|
}
|
|
|
|
function prepareRoman(counter) {
|
|
if (counter < 1 || counter > 4999) {
|
|
return counter.toString();
|
|
}
|
|
var num = counter;
|
|
var lookup = { M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1 }, roman = '', i;
|
|
for (i in lookup) {
|
|
while (num >= lookup[i]) {
|
|
roman += i;
|
|
num -= lookup[i];
|
|
}
|
|
}
|
|
return roman;
|
|
}
|
|
|
|
function prepareDecimal(counter) {
|
|
return counter.toString();
|
|
}
|
|
|
|
var counterText;
|
|
switch (type) {
|
|
case 'none':
|
|
counterText = null;
|
|
break;
|
|
|
|
case 'upper-alpha':
|
|
counterText = prepareAlpha(counter).toUpperCase();
|
|
break;
|
|
|
|
case 'lower-alpha':
|
|
counterText = prepareAlpha(counter);
|
|
break;
|
|
|
|
case 'upper-roman':
|
|
counterText = prepareRoman(counter);
|
|
break;
|
|
|
|
case 'lower-roman':
|
|
counterText = prepareRoman(counter).toLowerCase();
|
|
break;
|
|
|
|
case 'decimal':
|
|
default:
|
|
counterText = prepareDecimal(counter);
|
|
break;
|
|
}
|
|
|
|
if (counterText === null) {
|
|
return {};
|
|
}
|
|
|
|
if (separator) {
|
|
if (isArray(separator)) {
|
|
if (separator[0]) {
|
|
counterText = separator[0] + counterText;
|
|
}
|
|
|
|
if (separator[1]) {
|
|
counterText += separator[1];
|
|
}
|
|
counterText += ' ';
|
|
} else {
|
|
counterText += separator + ' ';
|
|
}
|
|
}
|
|
|
|
var textArray = { text: counterText };
|
|
var markerColor = styleStack.getProperty('markerColor');
|
|
if (markerColor) {
|
|
textArray.color = markerColor;
|
|
}
|
|
|
|
return { _inlines: this.textTools.buildInlines(textArray, styleStack).items };
|
|
};
|
|
|
|
DocMeasure.prototype.measureUnorderedList = function (node) {
|
|
var style = this.styleStack.clone();
|
|
var items = node.ul;
|
|
node.type = node.type || 'disc';
|
|
node._gapSize = this.gapSizeForList();
|
|
node._minWidth = 0;
|
|
node._maxWidth = 0;
|
|
|
|
for (var i = 0, l = items.length; i < l; i++) {
|
|
var item = items[i] = this.measureNode(items[i]);
|
|
|
|
if (!item.ol && !item.ul) {
|
|
item.listMarker = this.buildUnorderedMarker(style, node._gapSize, item.listType || node.type);
|
|
}
|
|
|
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth + node._gapSize.width);
|
|
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth + node._gapSize.width);
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureOrderedList = function (node) {
|
|
var style = this.styleStack.clone();
|
|
var items = node.ol;
|
|
node.type = node.type || 'decimal';
|
|
node.separator = node.separator || '.';
|
|
node.reversed = node.reversed || false;
|
|
if (!isNumber(node.start)) {
|
|
node.start = node.reversed ? items.length : 1;
|
|
}
|
|
node._gapSize = this.gapSizeForList();
|
|
node._minWidth = 0;
|
|
node._maxWidth = 0;
|
|
|
|
var counter = node.start;
|
|
for (var i = 0, l = items.length; i < l; i++) {
|
|
var item = items[i] = this.measureNode(items[i]);
|
|
|
|
if (!item.ol && !item.ul) {
|
|
var counterValue = isNumber(item.counter) ? item.counter : counter;
|
|
item.listMarker = this.buildOrderedMarker(counterValue, style, item.listType || node.type, node.separator);
|
|
if (item.listMarker._inlines) {
|
|
node._gapSize.width = Math.max(node._gapSize.width, item.listMarker._inlines[0].width);
|
|
}
|
|
} // TODO: else - nested lists numbering
|
|
|
|
node._minWidth = Math.max(node._minWidth, items[i]._minWidth);
|
|
node._maxWidth = Math.max(node._maxWidth, items[i]._maxWidth);
|
|
|
|
if (node.reversed) {
|
|
counter--;
|
|
} else {
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
node._minWidth += node._gapSize.width;
|
|
node._maxWidth += node._gapSize.width;
|
|
|
|
for (var i = 0, l = items.length; i < l; i++) {
|
|
var item = items[i];
|
|
if (!item.ol && !item.ul) {
|
|
item.listMarker._minWidth = item.listMarker._maxWidth = node._gapSize.width;
|
|
}
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureColumns = function (node) {
|
|
var columns = node.columns;
|
|
node._gap = this.styleStack.getProperty('columnGap') || 0;
|
|
|
|
for (var i = 0, l = columns.length; i < l; i++) {
|
|
columns[i] = this.measureNode(columns[i]);
|
|
}
|
|
|
|
var measures = ColumnCalculator.measureMinMax(columns);
|
|
|
|
var numGaps = (columns.length > 0) ? (columns.length - 1) : 0;
|
|
node._minWidth = measures.min + node._gap * numGaps;
|
|
node._maxWidth = measures.max + node._gap * numGaps;
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureTable = function (node) {
|
|
extendTableWidths(node);
|
|
node._layout = getLayout(this.tableLayouts);
|
|
node._offsets = getOffsets(node._layout);
|
|
|
|
var colSpans = [];
|
|
var col, row, cols, rows;
|
|
|
|
for (col = 0, cols = node.table.body[0].length; col < cols; col++) {
|
|
var c = node.table.widths[col];
|
|
c._minWidth = 0;
|
|
c._maxWidth = 0;
|
|
|
|
for (row = 0, rows = node.table.body.length; row < rows; row++) {
|
|
var rowData = node.table.body[row];
|
|
var data = rowData[col];
|
|
if (data === undefined) {
|
|
console.error('Malformed table row ', rowData, 'in node ', node);
|
|
throw 'Malformed table row, a cell is undefined.';
|
|
}
|
|
if (data === null) { // transform to object
|
|
data = '';
|
|
}
|
|
|
|
if (!data._span) {
|
|
data = rowData[col] = this.styleStack.auto(data, measureCb(this, data));
|
|
|
|
if (data.colSpan && data.colSpan > 1) {
|
|
markSpans(rowData, col, data.colSpan);
|
|
colSpans.push({ col: col, span: data.colSpan, minWidth: data._minWidth, maxWidth: data._maxWidth });
|
|
} else {
|
|
c._minWidth = Math.max(c._minWidth, data._minWidth);
|
|
c._maxWidth = Math.max(c._maxWidth, data._maxWidth);
|
|
}
|
|
}
|
|
|
|
if (data.rowSpan && data.rowSpan > 1) {
|
|
markVSpans(node.table, row, col, data.rowSpan);
|
|
}
|
|
}
|
|
}
|
|
|
|
extendWidthsForColSpans();
|
|
|
|
var measures = ColumnCalculator.measureMinMax(node.table.widths);
|
|
|
|
node._minWidth = measures.min + node._offsets.total;
|
|
node._maxWidth = measures.max + node._offsets.total;
|
|
|
|
return node;
|
|
|
|
function measureCb(_this, data) {
|
|
return function () {
|
|
if (isObject(data)) {
|
|
data.fillColor = _this.styleStack.getProperty('fillColor');
|
|
data.fillOpacity = _this.styleStack.getProperty('fillOpacity');
|
|
}
|
|
return _this.measureNode(data);
|
|
};
|
|
}
|
|
|
|
function getLayout(tableLayouts) {
|
|
var layout = node.layout;
|
|
|
|
if (isString(layout)) {
|
|
layout = tableLayouts[layout];
|
|
}
|
|
|
|
var defaultLayout = {
|
|
hLineWidth: function (i, node) {
|
|
return 1;
|
|
},
|
|
vLineWidth: function (i, node) {
|
|
return 1;
|
|
},
|
|
hLineColor: function (i, node) {
|
|
return 'black';
|
|
},
|
|
vLineColor: function (i, node) {
|
|
return 'black';
|
|
},
|
|
hLineStyle: function (i, node) {
|
|
return null;
|
|
},
|
|
vLineStyle: function (i, node) {
|
|
return null;
|
|
},
|
|
paddingLeft: function (i, node) {
|
|
return 4;
|
|
},
|
|
paddingRight: function (i, node) {
|
|
return 4;
|
|
},
|
|
paddingTop: function (i, node) {
|
|
return 2;
|
|
},
|
|
paddingBottom: function (i, node) {
|
|
return 2;
|
|
},
|
|
fillColor: function (i, node) {
|
|
return null;
|
|
},
|
|
fillOpacity: function (i, node) {
|
|
return 1;
|
|
},
|
|
defaultBorder: true
|
|
};
|
|
|
|
return pack(defaultLayout, layout);
|
|
}
|
|
|
|
function getOffsets(layout) {
|
|
var offsets = [];
|
|
var totalOffset = 0;
|
|
var prevRightPadding = 0;
|
|
|
|
for (var i = 0, l = node.table.widths.length; i < l; i++) {
|
|
var lOffset = prevRightPadding + layout.vLineWidth(i, node) + layout.paddingLeft(i, node);
|
|
offsets.push(lOffset);
|
|
totalOffset += lOffset;
|
|
prevRightPadding = layout.paddingRight(i, node);
|
|
}
|
|
|
|
totalOffset += prevRightPadding + layout.vLineWidth(node.table.widths.length, node);
|
|
|
|
return {
|
|
total: totalOffset,
|
|
offsets: offsets
|
|
};
|
|
}
|
|
|
|
function extendWidthsForColSpans() {
|
|
var q, j;
|
|
|
|
for (var i = 0, l = colSpans.length; i < l; i++) {
|
|
var span = colSpans[i];
|
|
|
|
var currentMinMax = getMinMax(span.col, span.span, node._offsets);
|
|
var minDifference = span.minWidth - currentMinMax.minWidth;
|
|
var maxDifference = span.maxWidth - currentMinMax.maxWidth;
|
|
|
|
if (minDifference > 0) {
|
|
q = minDifference / span.span;
|
|
|
|
for (j = 0; j < span.span; j++) {
|
|
node.table.widths[span.col + j]._minWidth += q;
|
|
}
|
|
}
|
|
|
|
if (maxDifference > 0) {
|
|
q = maxDifference / span.span;
|
|
|
|
for (j = 0; j < span.span; j++) {
|
|
node.table.widths[span.col + j]._maxWidth += q;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getMinMax(col, span, offsets) {
|
|
var result = { minWidth: 0, maxWidth: 0 };
|
|
|
|
for (var i = 0; i < span; i++) {
|
|
result.minWidth += node.table.widths[col + i]._minWidth + (i ? offsets.offsets[col + i] : 0);
|
|
result.maxWidth += node.table.widths[col + i]._maxWidth + (i ? offsets.offsets[col + i] : 0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function markSpans(rowData, col, span) {
|
|
for (var i = 1; i < span; i++) {
|
|
rowData[col + i] = {
|
|
_span: true,
|
|
_minWidth: 0,
|
|
_maxWidth: 0,
|
|
rowSpan: rowData[col].rowSpan
|
|
};
|
|
}
|
|
}
|
|
|
|
function markVSpans(table, row, col, span) {
|
|
for (var i = 1; i < span; i++) {
|
|
table.body[row + i][col] = {
|
|
_span: true,
|
|
_minWidth: 0,
|
|
_maxWidth: 0,
|
|
fillColor: table.body[row][col].fillColor,
|
|
fillOpacity: table.body[row][col].fillOpacity
|
|
};
|
|
}
|
|
}
|
|
|
|
function extendTableWidths(node) {
|
|
if (!node.table.widths) {
|
|
node.table.widths = 'auto';
|
|
}
|
|
|
|
if (isString(node.table.widths)) {
|
|
node.table.widths = [node.table.widths];
|
|
|
|
while (node.table.widths.length < node.table.body[0].length) {
|
|
node.table.widths.push(node.table.widths[node.table.widths.length - 1]);
|
|
}
|
|
}
|
|
|
|
for (var i = 0, l = node.table.widths.length; i < l; i++) {
|
|
var w = node.table.widths[i];
|
|
if (isNumber(w) || isString(w)) {
|
|
node.table.widths[i] = { width: w };
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
DocMeasure.prototype.measureCanvas = function (node) {
|
|
var w = 0, h = 0;
|
|
|
|
for (var i = 0, l = node.canvas.length; i < l; i++) {
|
|
var vector = node.canvas[i];
|
|
|
|
switch (vector.type) {
|
|
case 'ellipse':
|
|
w = Math.max(w, vector.x + vector.r1);
|
|
h = Math.max(h, vector.y + vector.r2);
|
|
break;
|
|
case 'rect':
|
|
w = Math.max(w, vector.x + vector.w);
|
|
h = Math.max(h, vector.y + vector.h);
|
|
break;
|
|
case 'line':
|
|
w = Math.max(w, vector.x1, vector.x2);
|
|
h = Math.max(h, vector.y1, vector.y2);
|
|
break;
|
|
case 'polyline':
|
|
for (var i2 = 0, l2 = vector.points.length; i2 < l2; i2++) {
|
|
w = Math.max(w, vector.points[i2].x);
|
|
h = Math.max(h, vector.points[i2].y);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
node._minWidth = node._maxWidth = w;
|
|
node._minHeight = node._maxHeight = h;
|
|
node._alignment = this.styleStack.getProperty('alignment');
|
|
|
|
return node;
|
|
};
|
|
|
|
DocMeasure.prototype.measureQr = function (node) {
|
|
node = qrEncoder.measure(node);
|
|
node._alignment = this.styleStack.getProperty('alignment');
|
|
return node;
|
|
};
|
|
|
|
module.exports = DocMeasure;
|