我想从Web应用程序生成PDF报告。 PDF应包含图表(饼图,条形图),表格,不同的字体和颜色。
应用程序的服务器端是Java,客户端是AngularJS(当然还有CSS3和HTML)。
两个主要选项:
在Java世界中,我发现了例如iText和JFreeChart,例如here。这里的问题是图表的设计在示例中看起来很糟糕,我不知道它是否可以通过我所拥有的样式指南(可以通过CSS轻松完成的设计)进行设计。
在JS世界中,我发现了html2canvas和pdfMake,例如here。这里的问题是我不确定从HTML转换到画布再转换为PDF在Angular应用程序中的效果是否正常。而且我不确定它是否转换了复杂的DOM元素,比如svg或canvas元素中的图表。
您对这些套餐有什么经验吗?您是否知道此任务,客户端或服务器的其他推荐软件包?
答案 0 :(得分:0)
想要分享我的解决方案......我选择了一个客户端解决方案。
我从jsPDF开始,但遇到了一些问题。例如,很难用我想要的样式转换表。
我选择pdfMake进行PDF生成,html2canvas进行复杂设计组件的截图,canvg进行d3js图表(svg图表)转换为画布(pdfMake可以添加画布作为文件的图像)。
我写了一个函数来获取我要转换为PDF的部分的HTML根的CSS类(记住它是单页应用程序),并且还获取了哪些HTML节点的元数据(再次,由他们的应该将CSS类添加到PDF(以及节点的类型 - table / text / image / svg)。
然后,通过DOM遍历,我浏览了要添加到PDF的元素,并按类型处理每个元素。部分代码(按类型遍历和切换案例):
$(htmlRootSelector).contents().each(function processNodes(index, element) {
var classMeta = getMetaByClass(element.className);
if (!classMeta) {
$(element).contents().each(processNodes);
return;
}
var pdfObj = {};
pdfObj.width = classMeta.width || angular.undefined;
pdfObj.height = classMeta.height || angular.undefined;
pdfObj.style = classMeta.style || angular.undefined;
pdfObj.pageBreak = classMeta.pageBreak || angular.undefined;
switch (classMeta.type) {
case 'text':
pdfObj.text = element.innerText;
pdfDefinition.content.push(pdfObj);
break;
case 'table':
var tableArray = [];
var headerArray = [];
var headers = $(element).find('th');
var rows = $(element).find('tr');
$.each(headers, function (i, header) {
headerArray.push({text: header.innerHTML, style: classMeta.style + '-header'});
});
tableArray.push(headerArray);
$.each(rows, function (i, row) {
var rowArray = [];
var cells = $(row).find('td');
if (cells.length) {
$.each(cells, function (j, cell) {
rowArray.push(i % 2 === 1 ? {text: cell.innerText, style: classMeta.style + '-odd-row'} : cell.innerText);
});
tableArray.push(rowArray);
}
});
pdfObj.table = {
widths: $.map(headers, function (d, i) {
return i === 0 ? 80 : '*';
}),
body: tableArray
};
pdfDefinition.content.push(pdfObj);
break;
case 'image':
html2CanvasCount++;
htmlToCanvas(element, pdfObj);
pdfDefinition.content.push(pdfObj);
break;
case 'svg':
svgToCanvas(element, pdfObj);
pdfDefinition.content.push(pdfObj);
break;
default:
break;
}
$(element).contents().each(processNodes);
});
这是一般的解决方案。 希望它会帮助别人。