在 IE 中使用表格创建 pdf 的问题

Issue creating pdf with tables in IE

目前,我正在使用 jspdf 最新版本和 jspdf-AutoTable 2.1.0 最新版本 以创建一个非常复杂的 PDF table .

它在 Chrome 和 FireFox 中非常有效(大惊喜!)但在 IE10 中,它呈现 pdf 非常糟糕(另一个大惊喜!)

这是 chrome 上 pdf 中最广泛的 table 之一的输出(当前为空)

这是IE10呈现的pdf

如您所见,它没有按应有的方式换行 header 列,也没有展开和显示第一列单元格并裁剪其中的文本。

为了保持我的自定义 table 样式,以及内容正确的样式,我调整并创建了我自己的 GetTableJSON 方法,这样我就可以检索和存储每个单独的单元格样式并应用它稍后在 createdHeaderCellcreatedCell 钩子上

这是用于创建具有自定义样式的 pdf 的完整代码

function DownloadSchedulePDF() {
    var orientation = landscape ? 'l' : 'p'
    var doc = new jsPDF(orientation, 'pt', paperFormat);
    doc.text('Header', 40, 50);
    var res = GetTableJSON($(".scheduleGrid table"));
    tableCellsStyles = res.styles;
    doc.autoTable(res.columns, res.data, {
        theme: 'plain',
        startY: 60,
        pageBreak: 'auto',
        margin: 20,
        width: 'auto',
        styles: {
            lineWidth: 0.01,
            lineColor: 0,
            fillStyle: 'DF',            
            halign: 'center',
            valign: 'middle',
            columnWidth: 'auto',
            overflow: 'linebreak'
        },
        createdHeaderCell: function (cell, data) {
            ApplyCellStyle(cell, "th", data.column.dataKey);
        },
        createdCell: function (cell, data) {
            ApplyCellStyle(cell, data.row.index, data.column.dataKey);
        },
        drawHeaderCell: function (cell, data) {
            //ApplyCellStyle(cell, "th", data.column.dataKey);
            //data.table.headerRow.cells[data.column.dataKey].styles = cell.styles;
            //ApplyCellStyle(data.table.headerRow.cells[data.column.dataKey], "th", data.column.dataKey);
        },
        drawCell: function (cell, data) {
            if (cell.raw === undefined)
                return false;
            if(cell.raw.indexOf("*") > -1) {
                var text = cell.raw.split("*")[0];
                var times = cell.raw.split("*")[1];
                doc.rect(cell.x, cell.y, cell.width, cell.height * times, 'FD');
                doc.autoTableText(text, cell.x + cell.width / 2, cell.y + cell.height * times / 2, {
                    halign: 'center',
                    valign: 'middle'
                });
                return false;
            }
        }
    });
    doc.save("schedule " + selectedDate.toLocaleDateString() + ".pdf");
}

function ApplyCellStyle(cell, x, y) {
    if(!pdfInColor)
        return;
    var styles = tableCellsStyles[x + "-" + y];
    if (styles === undefined)
        return;
    cell.styles.cellPadding = styles.cellPadding
    cell.styles.fillColor = styles.fillColor;
    cell.styles.textColor = styles.textColor;
    cell.styles.font = styles.font;
    cell.styles.fontStyle = styles.fontStyle;
}

Object.vals = function (o) {
    return Object.values
    ? Object.values(o)
    : Object.keys(o).map(function (k) { return o[k]; });
}
// direct copy of the plugin method adjusted in order to retrieve and store each cell style
function GetTableJSON (tableElem, includeHiddenElements) {
    includeHiddenElements = includeHiddenElements || false;

    var columns = {}, rows = [];

    var cellsStyle = {};

    var header = tableElem.rows[0];

    for (var k = 0; k < header.cells.length; k++) {
        var cell = header.cells[k];
        var style = window.getComputedStyle(cell);
        cellsStyle["th-" + k] = AdjustStyleProperties(style);
        if (includeHiddenElements || style.display !== 'none') {
            columns[k] = cell ? cell.textContent.trim() : '';
        }
    }

    for (var i = 1; i < tableElem.rows.length; i++) {
        var tableRow = tableElem.rows[i];
        var style = window.getComputedStyle(tableRow);
        if (includeHiddenElements || style.display !== 'none') {
            var rowData = [];
            for (var j in Object.keys(columns)) {
                var cell = tableRow.cells[j];
                style = window.getComputedStyle(cell);
                if (includeHiddenElements || style.display !== 'none') {
                    var val = cell
                        ? cell.hasChildNodes() && cell.childNodes[0].tagName !== undefined
                        ? cell.childNodes[0].textContent + (cell.getAttribute("rowSpan") ? "*" + cell.getAttribute("rowSpan") : '')
                        : cell.textContent.trim() 
                        : '';
                    cellsStyle[(i-1) + "-" + j] = cell 
                        ? cell.hasChildNodes() && cell.childNodes[0].tagName !== undefined 
                        ? AdjustStyleProperties(window.getComputedStyle(cell.childNodes[0]))
                        : AdjustStyleProperties(window.getComputedStyle(cell))
                        : {};
                    rowData.push(val);
                }
            }
            rows.push(rowData);
        }
    }

    return {columns: Object.vals(columns), rows: rows, data: rows, styles: cellsStyle}; // data prop deprecated
};

function AdjustStyleProperties(style) {
    return {
        cellPadding: parseInt(style.padding),
        fontSize: parseInt(style.fontSize),
        font: style.fontFamily, // helvetica, times, courier
        lineColor: ConvertToRGB(style.borderColor),
        lineWidth: parseInt(style.borderWidth) / 10,
        fontStyle: style.fontStyle, // normal, bold, italic, bolditalic
        overflow: 'linebreak', // visible, hidden, ellipsize or linebreak
        fillColor: ConvertToRGB(style.backgroundColor),
        textColor: ConvertToRGB(style.color),
        halign: 'center', // left, center, right
        valign: 'middle', // top, middle, bottom
        fillStyle: 'DF', // 'S', 'F' or 'DF' (stroke, fill or fill then stroke)
        rowHeight: parseInt(style.height),
        columnWidth: parseInt(style.width) // 'auto', 'wrap' or a number
        //columnWidth: 'auto'
    };
}

function ConvertToRGB(value) {
    if (value === undefined || value === '' || value === "transparent")
        value = [255, 255, 255];
    else if (value.indexOf("rgb") > -1)
        value = value.replace(/[^\d,]/g, '').split(',').map(function (x) { return parseInt(x) });
    else if (value.indexOf("#") > -1)
        value = value.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i
                         , function (m, r, g, b) { return '#' + r + r + g + g + b + b })
                .substring(1).match(/.{2}/g)
                .map(function (x) { return parseInt(x, 16) });
    else if (Array.isArray(value))
        return value;
    else {
        var canvas, context;
        canvas = document.createElement('canvas');
        canvas.height = 1;
        canvas.width = 1;
        context = canvas.getContext('2d');
        context.fillStyle = 'rgba(0, 0, 0, 0)';
        // We're reusing the canvas, so fill it with something predictable
        context.clearRect(0, 0, 1, 1);
        context.fillStyle = value;
        context.fillRect(0, 0, 1, 1);
        var imgData = context.getImageData(0, 0, 1, 1);
        value = imgData.data.slice
        ? imgData.data.slice(0, 3)
        : [imgData.data[0], imgData.data[1], imgData.data[2]];
    }
    return value;        
}

编辑:

根据要求,这是 table HTML 和 tableCellStyles 变量

的 JSON

https://jsfiddle.net/6ewqnwty/

由于 table 的大小以及 HTML 和 JSON 的字符数量,我将它们设置在单独的 fiddle 中。

编辑 2:

我刚刚使 fiddle 可运行,能够重现问题。

https://jsfiddle.net/6ewqnwty/1/

不像我在我的应用程序中那样完美,我能够检索带有样式的 pdf,只是缺少列 headers 文本,但至少是在 IE 上下载 pdf 时的问题仍然存在

运行 你的例子我得到 NaN 的 cellPadding。这也可能是它不适用于最新版本的原因。您可以做一些简单的事情,例如添加:

cell.styles.cellPadding = styles.cellPadding || 5;

在 ApplyCellStyle 中。你得到 NaN 的原因是 IE 显然 returns 空字符串而不是 chrome 等的 '0px'

另请注意,如果您升级,则不需要自己解析 html table,因为 cell.raw 在最新版本中设置为 html 元素。这意味着您可以使用 window.getComputedStyle(cell.raw).

之类的内容来解析样式