我使用chart.js生成一个包含多个图表的报表页面。我需要将此报告导出为PDF。通过搜索有许多解决方案,但我找不到具有多个canvas元素的解决方案。
唯一可用的解决方案似乎是遍历所有图像,然后使用图像重新创建报告,然后将其作为pdf下载。
有没有更简单/更有效的方法来实现这一目标?
<body>
<h1> Chart 1 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_1" width="50" height="50"></canvas>
</div>
<h1> Chart 2 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_2" width="50" height="50"></canvas>
</div>
<h1> Chart 3 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_3" width="50" height="50"></canvas>
</div>
</body>
答案 0 :(得分:9)
老实说,似乎最简单的方法就是提供一个“下载到PDF”链接,弹出浏览器的打印页面并指示用户选择“打印为pdf”。
如果这种方法对您(或您的用户)不起作用,那么这是一种粗略的方法。
基本上,我们会创建一个与报告页面大小相同的新canvas
元素,并将现有chart.js canvas
图表中的像素逐渐绘制到新的canvas
中。完成后,您可以使用jsPDF
将新画布作为图像添加到pdf文档中并下载文件。
这是一个实现此功能的示例实现。
$('#downloadPdf').click(function(event) {
// get size of report page
var reportPageHeight = $('#reportPage').innerHeight();
var reportPageWidth = $('#reportPage').innerWidth();
// create a new canvas object that we will populate with all other canvas objects
var pdfCanvas = $('<canvas />').attr({
id: "canvaspdf",
width: reportPageWidth,
height: reportPageHeight
});
// keep track canvas position
var pdfctx = $(pdfCanvas)[0].getContext('2d');
var pdfctxX = 0;
var pdfctxY = 0;
var buffer = 100;
// for each chart.js chart
$("canvas").each(function(index) {
// get the chart height/width
var canvasHeight = $(this).innerHeight();
var canvasWidth = $(this).innerWidth();
// draw the chart into the new canvas
pdfctx.drawImage($(this)[0], pdfctxX, pdfctxY, canvasWidth, canvasHeight);
pdfctxX += canvasWidth + buffer;
// our report page is in a grid pattern so replicate that in the new canvas
if (index % 2 === 1) {
pdfctxX = 0;
pdfctxY += canvasHeight + buffer;
}
});
// create new pdf and add our new canvas as an image
var pdf = new jsPDF('l', 'pt', [reportPageWidth, reportPageHeight]);
pdf.addImage($(pdfCanvas)[0], 'PNG', 0, 0);
// download the pdf
pdf.save('filename.pdf');
});
您可以在此codepen看到它的实际效果。
现在让我们谈谈这种方法的一些问题。首先,您必须控制新canvas
对象中每个chart.js canvas
的位置。唯一的方法是了解报表页面的结构并实现相同的结构。在我的例子中,我的图表是2x2网格,逻辑处理相应的。如果您有3x2网格或不同的网格,则必须更改定位逻辑。
最后,最终的pdf输出文件尺寸远大于原始图表页面(来自网络)。我认为原因是因为我的图表“容器”div延伸到整个页面。因此,您可能希望使用其他方法来设置新canvas
的大小。
长话短说,上面的例子是为了展示一种方法而不是你的最终解决方案。
祝你好运!答案 1 :(得分:0)
我在 vanilla javascript 中有一个可行的解决方案(尽管我使用了 ts 类型)并使用了 lib jsPdf,其中每个 pdf 页面都需要一个绘图:
let index = 1;
// create new pdf object
// if don't choose compress as true you will end up with a large pdf file
let pdf = new jsPDF({
orientation: 'landscape',
unit: 'px',
format: 'a4',
compress: true,
})
// search for the html element(s) you need
const canvas = document.querySelectorAll("canvas");
// here my size are in pixels since I configured that in the obj instance
let pageWidth = 400;
let pageHeight = 400;
let index = 1;
// traverse the array of canvas
canvas.forEach( (canva:HTMLCanvasElement) => {
// I added some options among others I added the type of the compression
// method: FAST
pdf.addImage(canva, 'PNG', 10, 10, pageWidth, pageHeight, `img${index}`, "FAST");
// so as to not end up with an extra pdf page at the end of the iteration
if (index < canvas.length) {
pdf.addPage();
}
index++;
});
// download the pdf
pdf.save('Reporte.pdf');