使用JavaScript和本地服务器将Highcharts导出为PDF(无需Internet连接)

14
我在我的应用程序中使用Highcharts(没有任何互联网连接)。
我在一个html页面中有多个图表,并且我想生成一个PDF报告,其中包含此页面上所有的图表。
如何在不将数据发送到互联网上的任何服务器的情况下完成此操作?
非常感谢您能提供的任何帮助或示例。 提前致谢 :)
5个回答

33
是的,这是可能的,但需要使用几个不同的库才能实现。第一个库是允许在浏览器中创建PDF的jsPDF。第二个库是canvg,它允许对SVG进行渲染和解析,而最酷的部分是它可以将SVG渲染到画布元素上。最后是Highcharts导出模块,它将允许我们将SVG发送到canvg,将其转换为数据URL,然后将其提供给jsPDF,以将其转换为PDF。
这里有一个例子http://fiddle.jshell.net/leighking2/dct9tfvn/,您还可以在其中查看源文件,这些文件需要包含在您的项目中。
因此,开始使用Highcharts提供了一个使用canvg进行导出并将图表保存为png的示例。由于您希望所有图像都在PDF中,因此这已经略微更改为仅返回数据URL。
// create canvas function from highcharts example http://jsfiddle.net/highcharts/PDnmQ/
(function (H) {
    H.Chart.prototype.createCanvas = function (divId) {
        var svg = this.getSVG(),
            width = parseInt(svg.match(/width="([0-9]+)"/)[1]),
            height = parseInt(svg.match(/height="([0-9]+)"/)[1]),
            canvas = document.createElement('canvas');

        canvas.setAttribute('width', width);
        canvas.setAttribute('height', height);

        if (canvas.getContext && canvas.getContext('2d')) {

            canvg(canvas, svg);

            return canvas.toDataURL("image/jpeg");

        } 
        else {
            alert("Your browser doesn't support this feature, please use a modern browser");
            return false;
        }

    }
}(Highcharts));

下面是我设置的示例,点击按钮即可导出。它将查找具有特定类别的所有元素(因此选择一个添加到所有图表元素中),然后调用它们的highcharts.createCanvas函数。

$('#export_all').click(function () {
    var doc = new jsPDF();

    // chart height defined here so each chart can be palced
    // in a different position
    var chartHeight = 80;

    // All units are in the set measurement for the document
    // This can be changed to "pt" (points), "mm" (Default), "cm", "in"
    doc.setFontSize(40);
    doc.text(35, 25, "My Exported Charts");

    //loop through each chart
    $('.myChart').each(function (index) {
        var imageData = $(this).highcharts().createCanvas();

        // add image to doc, if you have lots of charts,
        // you will need to check if you have gone bigger 
        // than a page and do doc.addPage() before adding 
        // another image.

        /**
        * addImage(imagedata, type, x, y, width, height)
        */
        doc.addImage(imageData, 'JPEG', 45, (index * chartHeight) + 40, 120, chartHeight);
    });


    //save with name
    doc.save('demo.pdf');
});

重要的是要注意,如果您有很多图表,您需要处理将它们放置在新页面上。jsPDF的文档看起来非常过时(虽然他们有一个很好的演示页面,但没有太多解释所有可能的选项),有一个addPage()函数,然后你可以调整宽度和高度,直到找到合适的大小。
最后一部分就是使用额外的选项设置图表,以便不显示通常会显示的每个图表的导出按钮。
//charts
$('#chart1').highcharts({
    navigation: {
            buttonOptions: {
                enabled: false
            }
        },

//this is just normal highcharts setup form here for two graphs see fiddle for full details

结果还不错,我对图表的质量印象深刻,因为我并没有期望太高,通过一些pdf位置和大小的调整,可以让它看起来更好。
这里是一个屏幕截图,显示了导出之前和之后进行的网络请求,导出时不会发出任何请求。 http://i.imgur.com/ppML6Gk.jpg 这是pdf的示例,http://i.imgur.com/6fQxLZf.png(在实际pdf中查看时效果更佳)。
快速本地试用的示例:https://github.com/leighquince/HighChartLocalExport

所有的转换都在浏览器中进行,这也是为什么我已经关闭了每个图表上的导出按钮。 - Quince
@Leon在问题中添加了网络请求的屏幕截图,以显示没有发送到高图表。 - Quince
好的,我会尝试现在设置,并告诉你结果。 - Quince
一切正常 - http://i.imgur.com/Yrh8mUb.png - 我还创建了一个快速的存储库,所以你可以下载并尝试自己 - https://github.com/leighquince/HighChartLocalExport - Quince
谢谢Quince!干得好 :) - Leon
显示剩余7条评论

1
你需要设置自己的导出服务器,可以本地设置,就像在文章中所述。

1
这是一个使用pdfmake库的示例:
html:
<div id="chart_exchange" style="width: 450px; height: 400px; margin: 0 auto"></div>
<button id="export">export</button>
<canvas id="chart_exchange_canvas" width="450" height="400" style="display: none;"></canvas>

javascript:

function drawInlineSVG(svgElement, canvas_id, callback) {
  var can = document.getElementById(canvas_id);
  var ctx = can.getContext('2d');

  var img = new Image();
  img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgElement))));
  img.onload = function() {
    ctx.drawImage(img, 0, 0);
    callback(can.toDataURL("image/png"));
  }
}

完整可运行代码:

https://jsfiddle.net/dimitrisscript/f6sbdsps/

它将导出图表,那文字呢? - yasir_mughal
在 PDF 文件内有文本:"Hello World"。 - Dimitris Siakavelis
这是一个很好的解决方案。不过,我想知道是否可以在不使用jQuery的情况下实现。 - cbrawl

0

或许这个链接可以帮到你。

http://bit.ly/1IYJIyF

请尝试参考导出属性(fallbackToExportServer: false)和需要包含的必要文件(offline-exporting.js)。

至于一次性全部导出部分,目前我自己也还在尝试中。如果有任何更新,我会在这里更新。


0

这个问题有点旧,但最近我也在做同样的事情,遇到了一些问题。

我使用了jsPDF库: https://github.com/MrRio/jsPDF

我遇到的问题包括jsPDF不支持由high chart导出的SVG图像,以及图像模糊和低质量。

以下是我用来将两个图表放入一个pdf文档中的解决方案:

function createPDF() {
var doc = new jsPDF('p', 'pt', 'a4'); //Create pdf

if ($('#chart1').length > 0) {
    var chartSVG = $('#chart1').highcharts().getSVG();
    var chartImg = new Image();

    chartImg.onload = function () {

        var w = 762;
        var h = 600;

        var chartCanvas = document.createElement('canvas');
        chartCanvas.width = w * 2;
        chartCanvas.height = h * 2;
        chartCanvas.style.width = w + 'px';
        chartCanvas.style.height = h + 'px';
        var context = chartCanvas.getContext('2d');
        chartCanvas.webkitImageSmoothingEnabled = true;
        chartCanvas.mozImageSmoothingEnabled = true;
        chartCanvas.imageSmoothingEnabled = true;
        chartCanvas.imageSmoothingQuality = "high";
        context.scale(2, 2);
        chartCanvas.getContext('2d').drawImage(chartImg, 0, 0, 762, 600);

        var chartImgData = chartCanvas.toDataURL("image/png");
        doc.addImage(chartImgData, 'png', 40, 260, 250, 275);

        if ($('#chart2').length > 0) {
            var chart2SVG = $('#chart2').highcharts().getSVG(),
                chart2Img = new Image();

            chart2Img.onload = function () {

                var chart2Canvas = document.createElement('canvas');
                chart2Canvas.width = w * 2;
                chart2Canvas.height = h * 2;
                chart2Canvas.style.width = w + 'px';
                chart2Canvas.style.height = h + 'px';
                var context = chart2Canvas.getContext('2d');
                chart2Canvas.webkitImageSmoothingEnabled = true;
                chart2Canvas.mozImageSmoothingEnabled = true;
                chart2Canvas.imageSmoothingEnabled = true;
                chart2Canvas.imageSmoothingQuality = "high";
                context.scale(2, 2);
                chart2Canvas.getContext('2d').drawImage(chart2Img, 0, 0, 762, 600);

                var chart2ImgData = chart2Canvas.toDataURL("image/png");
                doc.addImage(chart2ImgData, 'PNG', 300, 260, 250, 275);

                doc.save('ChartReport.pdf');
            }

            chart2Img.src = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(chart2SVG)));
        }
    }
    chartImg.src = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(chartSVG)));
}
}

需要包括的脚本:

 <script src="http://code.highcharts.com/highcharts.js"></script>
 <script src="http://code.highcharts.com/modules/exporting.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>

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