pdfmake
Version:
Client/server side PDF printing in pure JavaScript
158 lines (136 loc) • 5.02 kB
JavaScript
var isString = require('./helpers').isString;
function buildColumnWidths(columns, availableWidth, offsetTotal = 0, tableNode) {
var autoColumns = [],
autoMin = 0, autoMax = 0,
starColumns = [],
starMaxMin = 0,
starMaxMax = 0,
fixedColumns = [],
initial_availableWidth = availableWidth;
columns.forEach(function (column) {
if (isAutoColumn(column)) {
autoColumns.push(column);
autoMin += column._minWidth;
autoMax += column._maxWidth;
} else if (isStarColumn(column)) {
starColumns.push(column);
starMaxMin = Math.max(starMaxMin, column._minWidth);
starMaxMax = Math.max(starMaxMax, column._maxWidth);
} else {
fixedColumns.push(column);
}
});
fixedColumns.forEach(function (col, colIndex) {
// width specified as %
if (isString(col.width) && /\d+%/.test(col.width)) {
// In tables we have to take into consideration the reserved width for paddings and borders
var reservedWidth = 0;
if (tableNode) {
var paddingLeft = tableNode._layout.paddingLeft(colIndex, tableNode);
var paddingRight = tableNode._layout.paddingRight(colIndex, tableNode);
var borderLeft = tableNode._layout.vLineWidth(colIndex, tableNode);
var borderRight = tableNode._layout.vLineWidth(colIndex + 1, tableNode);
if (colIndex === 0) {
// first column assumes whole borderLeft and half of border right
reservedWidth = paddingLeft + paddingRight + borderLeft + (borderRight / 2);
} else if (colIndex === fixedColumns.length - 1) {
// last column assumes whole borderRight and half of border left
reservedWidth = paddingLeft + paddingRight + (borderLeft / 2) + borderRight;
} else {
// Columns in the middle assume half of each border
reservedWidth = paddingLeft + paddingRight + (borderLeft / 2) + (borderRight / 2);
}
}
var totalAvailableWidth = initial_availableWidth + offsetTotal;
col.width = (parseFloat(col.width) * totalAvailableWidth / 100) - reservedWidth;
}
if (col.width < (col._minWidth) && col.elasticWidth) {
col._calcWidth = col._minWidth;
} else {
col._calcWidth = col.width;
}
availableWidth -= col._calcWidth;
});
// http://www.freesoft.org/CIE/RFC/1942/18.htm
// http://www.w3.org/TR/CSS2/tables.html#width-layout
// http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm
var minW = autoMin + starMaxMin * starColumns.length;
var maxW = autoMax + starMaxMax * starColumns.length;
if (minW >= availableWidth) {
// case 1 - there's no way to fit all columns within available width
// that's actually pretty bad situation with PDF as we have no horizontal scroll
// no easy workaround (unless we decide, in the future, to split single words)
// currently we simply use minWidths for all columns
autoColumns.forEach(function (col) {
col._calcWidth = col._minWidth;
});
starColumns.forEach(function (col) {
col._calcWidth = starMaxMin; // starMaxMin already contains padding
});
} else {
if (maxW < availableWidth) {
// case 2 - we can fit rest of the table within available space
autoColumns.forEach(function (col) {
col._calcWidth = col._maxWidth;
availableWidth -= col._calcWidth;
});
} else {
// maxW is too large, but minW fits within available width
var W = availableWidth - minW;
var D = maxW - minW;
autoColumns.forEach(function (col) {
var d = col._maxWidth - col._minWidth;
col._calcWidth = col._minWidth + d * W / D;
availableWidth -= col._calcWidth;
});
}
if (starColumns.length > 0) {
var starSize = availableWidth / starColumns.length;
starColumns.forEach(function (col) {
col._calcWidth = starSize;
});
}
}
}
function isAutoColumn(column) {
return column.width === 'auto';
}
function isStarColumn(column) {
return column.width === null || column.width === undefined || column.width === '*' || column.width === 'star';
}
//TODO: refactor and reuse in measureTable
function measureMinMax(columns) {
var result = { min: 0, max: 0 };
var maxStar = { min: 0, max: 0 };
var starCount = 0;
for (var i = 0, l = columns.length; i < l; i++) {
var c = columns[i];
if (isStarColumn(c)) {
maxStar.min = Math.max(maxStar.min, c._minWidth);
maxStar.max = Math.max(maxStar.max, c._maxWidth);
starCount++;
} else if (isAutoColumn(c)) {
result.min += c._minWidth;
result.max += c._maxWidth;
} else {
result.min += ((c.width !== undefined && c.width) || c._minWidth);
result.max += ((c.width !== undefined && c.width) || c._maxWidth);
}
}
if (starCount) {
result.min += starCount * maxStar.min;
result.max += starCount * maxStar.max;
}
return result;
}
/**
* Calculates column widths
* @private
*/
module.exports = {
buildColumnWidths: buildColumnWidths,
measureMinMax: measureMinMax,
isAutoColumn: isAutoColumn,
isStarColumn: isStarColumn
};
;