具有多个 chart.js 图表的页面到 pdf
我使用 chart.js 生成了一个包含多个图表的报告页面.我需要将此报告导出为 PDF.可以通过搜索获得许多解决方案,但我找不到具有多个画布元素的解决方案.
I have used chart.js to generate a report page that has multiple charts. I need to export this report to PDF. There are many solutions available via search, but I cannot find one which has multiple canvas elements.
唯一可用的解决方案似乎是遍历所有图像,并使用图像重新创建报告,然后将其下载为 pdf.
The only available solution seems to be to loop through all the images, and recreate the report using the images, and then download that as a pdf.
有没有更简单/更有效的方法来完成这个?
Is there any simpler/more efficient way to accomplish this?
<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>
推荐答案
老实说,似乎最简单的方法就是提供一个下载到 PDF"链接,该链接会弹出浏览器的打印页面并指示用户选择打印为 pdf".
Honestly, it seems like the easiest approach would be to just provide a "download to PDF" link that pops up the browser's print page and instruct to user to select "print as pdf".
如果这种方法对您(或您的用户)不起作用,那么这里有一个粗略的方法.
If that approach doesn't work for you (or your users), then here is a rough way to do it.
基本上,我们创建一个新的 canvas
元素,它是您的报告页面的大小,并将现有 chart.js canvas
图表中的像素增量绘制到新的 <代码>画布代码>.完成后,您可以使用 jsPDF
将新画布作为图像添加到 pdf 文档并下载文件.
Basically, we create a new canvas
element that is the size of your report page and incrementally paint the pixels from your existing chart.js canvas
charts into the new canvas
. Once that is done, then you can use jsPDF
to add the new canvas to a pdf document as an image and download the file.
这是一个实现这一点的示例.
Here is an example implementation that does just that.
$('#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 中看到它的实际效果.
You can see it in action at this codepen.
现在让我们谈谈这种方法的一些问题.首先,您必须控制每个 chart.js canvas
在新 canvas
对象中的位置.做到这一点的唯一方法是了解报告页面的结构并实施相同的结构.在我的示例中,我的图表位于 2x2 网格中,逻辑会相应地处理此问题.如果您有一个 3x2 网格或其他东西,那么您将不得不更改定位逻辑.
Now let's talk about some gotchas with this approach. First, you have to control the position of each chart.js canvas
in the new canvas
object. The only way to do that is to have an understanding of how your report page is structured and implement that same structure. In my example, my charts are in a 2x2 grid and the logic handles this accordingly. If you had a 3x2 grid or something different then you would have to change the positioning logic.
最后,最终的 pdf 输出文件尺寸比原始图表页面(来自网络)大得多.我认为原因是因为我的图表容器"div 横跨整个页面.因此,您可能希望使用不同的方法来设置新 canvas
的大小.
Lastly, the final pdf output file dimensions are much larger than the original chart page (from the web). I think the reason is because my chart "container" div stretches across the full page. Therefore, you probably want to use a different approach for setting the size of your new canvas
.
长话短说,上面的示例旨在展示一种方法,而不是您的最终解决方案.
So long story short, the above example is meant to demonstrate an approach and not be your final solution.
祝你好运!
相关文章