Chartjs + jsPDF = 图片模糊问题

9
我是一个有用的助手,可以为您翻译文本。

我遇到了一些导出图表到PDF的问题。

我有这个div

    <div id="chart-area">
    <button type="button" id="btnPrint_" onClick="Print1()">Print</button>
    <?php echo '<h2 id="title">'.$_SESSION['team_name'].'</h2>'; ?>
        <canvas id="myChart" width="800" height="400"></canvas>
        <div id="legend"></div>
    </div>

我正在使用ChartJS创建图表。

$( document ).ready(function(){
    var helpers = Chart.helpers;
    var canvas = document.getElementById('myChart');
    var data = {
        labels: unique_dates,
        datasets: [
            {
                label: "Ticket Count",
                fillColor: "rgba(107, 110, 111, 0.6)",
                strokeColor: "rgba(107, 110, 111, 0.6)",
                highlightFill: "rgba(107, 110, 111, 0.6)",
                highlightStroke: "rgba(151,137,200,1)",
                data: ticket_count
            },
            {
                label: "Subsidy Count",
                fillColor: "rgba(8, 126, 210,0.5)",
                strokeColor: "rgba(8, 126, 210,0.8)",
                highlightFill: "rgba(220,220,220,0.75)",
                highlightStroke: "rgba(220,220,220,1)",
                data: subsidy_count
            }
        ]
    }


  var bar = new Chart(canvas.getContext('2d')).Bar(data, {
  tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>kb",
  animation: true,
});
// 
var legendHolder = document.createElement('div');
legendHolder.innerHTML = bar.generateLegend();

document.getElementById('legend').appendChild(legendHolder.firstChild); 

});

当我点击“btnPrint_”按钮时,我希望将我的图表导出为PDF文件,就像这样。
function Print1() {
            var title = $("#title").text();
            var doc = new jsPDF('l', 'mm',[210, 297]);
           html2canvas($("#myChart"), {
                onrendered: function(canvas) {         
                    var imgData = canvas.toDataURL('image/png',1.0);                  
                    doc.text(130,15,title+" GT Log");
                    doc.addImage(imgData, 'PNG',20,30,0,130); 
                    doc.addHTML(canvas);
                    doc.save(title+'gt_log.pdf');             
                    }       
            });

}

问题是我的图表在pdf文件中非常模糊。

有什么办法可以解决这个问题吗?

这是我第一次使用ChartJS和jsPDF,可能我做错了什么。

谢谢!

3个回答

10

分辨率取决于画布大小。当您增加画布的宽度和高度时,下载PDF文件时的分辨率会更好。

然而,您可能不希望太大幅度地增加画布大小,所以一个技巧是创建一个隐藏的画布,并将其宽度和高度增加,使用它来打印图表并创建PDF,从而获得更好的PDF质量。

这里有一个演示,其中提供了两个选项,一个选项可以从原始画布/图表创建PDF,另一个选项可以从隐藏的画布/图表创建新的PDF。您可以看到比较两个结果时,质量提高了很多。

https://jsfiddle.net/crabbly/kL68ey5z/

我不认为这是最好的解决方案,但这是我能想到的唯一方法来提高PDF图表文件的质量。我目前正在研究这两个库,特别是jsPDF在创建文档时如何处理wh参数。

此外,Chart.js确实配备了一个内置函数来从图表中提取图像(.toBase64Image()),但是在我的测试中质量似乎更差。


我知道已经有一段时间了,但你是否尝试过输出PNG文件而不是JPEG文件?我对生成JPEG文件使用的压缩方案以及它们丢失图表中内置透明度的事实表示怀疑。 - Ecksters
@Ecksters,大多数情况下我会使用png格式,它的效果很好。而且正如你所提到的,它可以保持图形的透明度。 https://jsfiddle.net/crabbly/kL68ey5z/380 - crabbly
这个答案来自2016年,那时是一个非常好的解决方案。今天,Chartjs本身提供了一个选项来设置分辨率,以便在PDF中看起来很好。https://dev59.com/TJPfa4cB1Zd3GeqPADWs#67654192。 - Sarah Trees

7
自从几个版本之前,Chart.js就有了devicePixelRatio参数。默认情况下,画布以显示器的DPI数值进行渲染,通常为96或Retina - 适用于屏幕,但不适合打印。
如果您增加此值,则会创建更多像素。 扩大该值可将图表导出为Base64图像,并使其具备打印质量,但这个值不会影响在显示器上显示的图表。
在我的情况下,我将该值设置为1.5。
options:{
      devicePixelRatio: 1.5
}

文档:https://www.chartjs.org/docs/3.0.2/configuration/device-pixel-ratio.html 非常出色地发挥作用...


更新 devicePixelRatio 对我很有帮助。谢谢。 - Wasti

1
我一直在做一个项目,试图使用Chartjs生成图表,然后使用Chrome的打印为PDF功能进行打印,但发现Chartjs生成的图表质量较差。在阅读了StackOverflow和Github上的各种讨论后,我开发了一个解决方案,对我来说足够好用。
在我的情况下,我需要固定大小的图表,并且不能使其具有响应性,因为我需要它们正确地适合打印页面。我使用样式标签设置大小: 我发现,如果你在图表中设置"responsive: false",然后像那样使用样式标签,Chartjs不会改变图表的大小。使用任何其他方法,比如设置宽度或高度(而不是样式宽度或高度),或者使用CSS类,都无法正确设置它。只有当我为该元素设置内联样式标签时,Chartjs才能正常工作。
总之,对我有用的技巧是让Chartjs渲染更大的图表,然后将其缩小到更小的尺寸,以便正确适合我的页面。
假设我们出于某种原因需要一个300x300像素的图表,并且将其打印到PDF时它看起来很差。我们需要让Chartjs把这个图表绘制成一个更大的图表,然后将其缩小到300x300。在我的项目中,我让Chartjs绘制2倍大小的图表。因此,对于这个示例,我会创建一个大小为600x600的画布元素,如下所示:
<canvas style="width: 600px; height: 600px;" class="graph" />

同时,我有一个名为 "graph" 的 CSS 类,高度和宽度设置为 300 像素。然而,由于内联样式的存在,图表不会以 300 像素渲染。
您可以像通常一样制作图表,但是在制作图表的代码行之后立即删除图表的内联样式标签。我发现当您这样做时,Chart.js 将以更大的 600x600 大小绘制图表,但随即将图表大小调整为 300x300。以下是代码示例:

var ctx = canvas.getContext('2d'); var mychart = new Chart( ctx ,{ .... }); canvas.removeAttribute("style");

canvas.removeAttribute 会移除内联样式标签,因此 css 类会生效并立即导致画布以较小的尺寸重新渲染。没有任何闪烁或指示发生了什么,但我发现这样可以得到更高质量的图表。
这还有一个问题。例如,为了让图表看起来正确,您需要将其设计为较大的600x600大小。当您以较大的尺寸绘制图表时,线条和字体不会被调整大小,因此一切都看起来非常小。我必须手动设置我的图表到较大的尺寸来设计它,并找出适合图形的好字体和线条大小,然后在此处进行调整大小技巧。 我还发现,仅使用较小的图表并使线条更粗或字体更大似乎没有将所有内容先放大,然后再将其呈现为较小尺寸那样的效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接