【问题标题】:Generating PDF using multiple google charts and jspdf使用多个谷歌图表和 jspdf 生成 PDF
【发布时间】:2017-02-14 23:04:35
【问题描述】:

添加到这个 stackoverflow 问题:Generating pdf using multiple graphs using html2canvas and jspdf

我尝试使用 Promise javascript api 如下:

function GeneratePDFforCharts(divNamesForPDF)
{


var arrayOfPromises = [];

//Note: Checking if the browser supports Promises
if (window.Promise) {

    for (var i = 0; i < divNamesForPDF.length; i++)
    {
        var promise = new Promise(function (resolve, reject) {
            //asynchronous code goes here
            //Note: The Promise is passed a callback function. The callback takes two arguments, resolve and reject.
            //Note: If everything is successful, the promise is fullfilled by calling resolve(). In case of an error, reject() is called with an Error object.
            var element = $(divNamesForPDF[i]).get(0);
            html2canvas(element, {
                onrendered: function (canvas) {
                    resolve(canvas.toDataURL('image/png'));
                }
            });
        });
        arrayOfPromises.push(promise);
    }

    Promise.all(arrayOfPromises).then(function (canvases) {
        var count = 0;
        var pageNumber = 1;

        var doc = new jsPDF('l', 'mm', [297, 210], true); //true is set for pdf compression

        for (var i = 0; i < canvases.length; i++)
        {
            if (isOdd(count)) //2nd chart
            {
                doc.addImage(canvases[i], 'PNG', 10, 105, 270, 100, null, 'FAST'); //x, y, width, height - FAST is used for png compression
                var pageNo = pageNumber.toString();
                doc.text(140, 207, pageNo); //x, y, text
                pageNumber++;
            }
            else //1st chart
            {
                if (count != 0)
                {
                    doc.addPage();
                }
                doc.addImage(canvases[i], 'PNG', 10, 5, 270, 100, null, 'FAST');
            }
            count++;
        }

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

}

}

我正在做的是发送 33 个代表谷歌图表面板的 divnames 作为 jspdf 生成 pdf 的参数。

问题:但是,Chrome 浏览器在单击生成 pdf 按钮时崩溃。调试后似乎它正在通过for循环。但是它永远不会出现在 Promise.all 函数中。

另外,最好指出以下几点:

  1. 例如,当我只传递 4 个 div 时,pdf 生成成功。所以这是 chrome 没有处理生成的 base 64 数量的问题?
  2. 我在将图像添加到 pdf 时使用了“FAST”参数,以使其也被压缩。

对此有何反馈?请问我是不是做错了什么?

【问题讨论】:

    标签: javascript pdf promise google-visualization jspdf


    【解决方案1】:

    似乎代码可以工作,但扩展性不太好。

    有可能通过并行执行所有操作,javascript 的垃圾收集 (GC) 没有机会清除中间对象,并且过大的堆会导致崩溃。

    按顺序执行操作可能会产生积极影响。代码只是从问题中的代码派生出来的。

    首先,一个适配器函数,它承诺html2canvas()

    function html2canvasAsync(element) {
        return new Promise(function(resolve, reject) {
            html2canvas(element, {
                onrendered: function (canvas) {
                    resolve(canvas.toDataURL('image/png'));
                }
            });
        });
    };
    

    现在调用divNamesForPDF.reduce(...)来序列化异步操作并逐步添加到jsPDF中doc

    function GeneratePDFforCharts(divNamesForPDF) {
        if (window.Promise) {
            var doc = new jsPDF('l', 'mm', [297, 210], true); //true is set for pdf compression
            return divNamesForPDF.reduce(function(p, name, i) {
                return p.then(function(pageNumber) {
                    return html2canvasAsync($(name).get(0)) // or `document.getElementById(name)` ?
                    // return html2canvasAsync(document.getElementById(name)) // possibly?
                    .then(function(canvas) {
                        if (isOdd(i)) { // odds
                            doc.addImage(canvas, 'PNG', 10, 105, 270, 100, null, 'FAST'); //x, y, width, height - FAST is used for png compression
                            doc.text(140, 207, pageNumber.toString()); //x, y, text
                            pageNumber++;
                        } else { // evens
                            if (i > 0) {
                                doc.addPage();
                            }
                            doc.addImage(canvas, 'PNG', 10, 5, 270, 100, null, 'FAST');
                        }
                        return pageNumber;
                    }).catch(function(e) {
                        // Error handling is a good idea
                        console.log(e);
                        doc.text(35, 25, e.message); // possibly add the error message to doc
                    });
                });
            }, Promise.resolve(1)) // starter promise resolved with page number 1
            .then(function() {
                doc.save('IEA_Global_MonthlyStocks_Analytics.pdf');
            });
        }
    }
    

    只检查语法

    正如我所说,这并不比“可能”解决问题更好。试一试不花任何钱。可能发生的最坏情况是 Chrome 再次崩溃。

    【讨论】:

    • 这是上帝派来的 :) 非常感谢 Roamer。我可以确认它没有崩溃并且可以很好地扩展。目前需要1分19秒,你知道如何处理可以更快吗?
    • 哇!很高兴听到它有效,尽管 1 分 19 秒确实很长。不幸的是,这种方法通过减慢速度来解决崩溃问题 - 串行操作而不是并行操作 - 因此,对于客户端解决方案,您似乎陷入了“慢”与“根本不”的困境。 “企业”解决方案是将部分或全部工作委托给具有大量 RAM 的专用重量级服务器。我只知道如何实现这一目标。
    猜你喜欢
    • 2017-03-29
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多