如何在NodeJS中使用图表和谷歌地图从html生成PDF

问题描述

我想在 Nodejs 中将 HTML 导出为 PDF。 我的 HTML 文件包含图表、图形、图像和表格数据。 我已经创建了带有把手解析的 HTML,并为 pdf 的 HTML 创建了一个公共 URL。 我尝试使用 HTML-PDF NPM 包将 HTML 导出为 pdf,但它无法加载图表、地图等,只是加载带有表格数据的简单 HTML。 这是我如何尝试使用 HTML 页面链接导出的示例:

const requestify = require('requestify');
const path = require("path");
const pdf = require('html-pdf');
const externalURL = `myurl.com/pdf-html`;
requestify.get(externalURL).then(function(response) {
    // Get the raw HTML response body
    const html = response.body;
    const config = { format: 'A4',"base": `file:///${path.resolve("./public")}`};
    // Create the PDF
    pdf.create(html,config).toFile('./public/generated.pdf',function(err,response) {
        if (err) {
            console.log("error");
            return console.log(err);
        }
        res.attachment('report.pdf');
        return res.status(200).send(response);
      });
 });

这是我尝试以 PDF 格式导出的 HTML 文件

<html>

<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <style>
        #map-canvas {
            width: 500px;
            height: 350px;
        }
    </style>
</head>

<body>
    <h1>HTML to PDF</h1>
    <div id="chart"></div>
    <div id="map-canvas"></div>
    <table>
        <thead>
            <th>Site</th>
            <th>Site Name</th>
            <th>Location</th>
            <th>Status</th>
        </thead>
        <tbody>
            {{#if records}}
                {{#each records}}
                    <tr>
                        <td><img src="{{this.site}}" style="width: 25px;height: 35px;"></img></td>
                        <td>{{this.siteName}}</td>
                        <td>{{this.location}}</td>
                        <td>{{this.status}}</td>
                    </tr>
                {{/each}}
            {{/if}}
        </tbody>
    </table>
    <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>        

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places,geometry"></script>

    <script>
        $(document).ready(function() {
            var options = {
                chart: { type: 'line' },series: [{
                    name: 'sales',data: [30,40,35,50,49,60,70,91,125]
                }],xaxis: {
                    categories: [1991,1992,1993,1994,1995,1996,1997,1998,1999]
                }
            }
            var chart = new ApexCharts(document.querySelector("#chart"),options);
            chart.render();

            function initialize() {
                var myLatLng = new google.maps.LatLng(45.4375,12.3358),myOptions = {
                        zoom: 5,center: myLatLng,mapTypeId: google.maps.MapTypeId.ROADMAP
                    },map = new google.maps.Map(document.getElementById('map-canvas'),myOptions),marker = new google.maps.Marker({
                        position: myLatLng,map: map
                    });

                marker.setMap(map);
                moveMarker(map,marker);
            }

            function moveMarker(map,marker) {
                //delayed so you can see it move
                setTimeout(function() {
                    marker.setPosition(new google.maps.LatLng(45.4375,12.3358));
                    map.panTo(new google.maps.LatLng(45.4375,12.3358));
                },1500);
            };

            initialize();
        });
    </script>
</body>

</html>

另外,我收到以下错误

message=html-pdf: Received the exit code '1'
html-pdf: Evaluation - ReferenceError: Can't find variable: ApexCharts
Stack: at file:////path/to/project/public,stack=Error: html-pdf: Received the exit code '1'
html-pdf: Evaluation - ReferenceError: Can't find variable: ApexCharts
Stack: at file:////path/to/project/public

at ChildProcess.respond (path/to/project/node_modules/html-pdf/lib/pdf.js:121:31)
at ChildProcess.emit (events.js:315:20)
at Process.ChildProcess._handle.onexit (internal/child_process.js:277:12)
enter code here

我也尝试过 puppeteer NPM 包,但是这个包也有同样的问题,无法加载图表和地图。 无法在 PDF 中获取完全加载的 HTML。

所以任何人都知道如何导出包含地图、图表、图像、表格等的 HTML。 非常感谢您的帮助。

解决方法

我是使用 Puppeteer 完成的。 我在 NodeJS 中创建了一个路由,它在我的 PDF 中呈现关于我想要的 HTML。 此路由无需登录即可访问,因此不需要登录。 在我的 HTML 文件中,我添加了动态图表、谷歌地图、图像和表格列表。

我通过在导出 PDF 路径中编写以下内容创建了 PDF:

const path = require("path");
const puppeteer = require('puppeteer');

// launch a new chrome instance
const browser = await puppeteer.launch({
     headless: true
});

// create a new page
const page = await browser.newPage()

// Go to URL of HTML that I want to export in PDF
await page.goto(`domain.com/my-pdf-html`,{
       waitUntil: "networkidle0"
});

// Create pdf file of opened page
const pdf = await page.pdf({
    printBackground: true,format: 'A4',path: `${path.resolve("./public/my-report.pdf")}`
});

// close the browser    
await browser.close();

// Return generated pdf in response
res.contentType("application/pdf");
return res.status(200).send(pdf);

我希望这也能帮助别人。