使用Puppeteer生成echarts图片

Puppeteer简介

Puppeteer 是一个用于控制 Headless Chrome 或 Chromium 浏览器的 Node.js 库。它提供了一个高层次的 API,能够让你以编程方式操作浏览器,从而实现自动化任务,比如生成页面截图和 PDF、抓取网页内容、自动化表单提交、UI 测试等。

简单来讲我们部署一个虚拟浏览器, 通过后台渲染然后把图片输出

安装Puppeteer

使用node.js可以直接将Puppeteer部署为服务

bash 复制代码
mkdir puppeteer-service
cd puppeteer-service
npm init -y
npm install puppeteer
npm install express

编写js脚本

编写一个用于启动的js脚本, 起名 为indx.js, 将其放在根目录下

javascript 复制代码
const express = require('express');
const puppeteer = require('puppeteer');
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');

const app = express();
app.use(bodyParser.json());

app.post('/generate-echarts', async (req, res) => {
    const { templateName, data } = req.body;
	console.error('请求参数:', data);
    if (!templateName) {
        return res.status(400).send('缺少模板名称');
    }

    if (!data) {
        return res.status(400).send('缺少ECharts配置参数');
    }

    const templatePath = path.join(__dirname, 'templates', `${templateName}.html`);

    if (!fs.existsSync(templatePath)) {
        return res.status(404).send('模板文件不存在');
    }

    let browser;
    try {
        // 启动无头浏览器
        browser = await puppeteer.launch({ headless: true });
        const page = await browser.newPage();
        const content = fs.readFileSync(templatePath, 'utf-8');

        await page.setContent(content);

        // 等待 #chart 元素加载完成
        await page.waitForSelector('#chart', { timeout: 60000 });

        // 将配置参数传递给页面并渲染图表
        await page.evaluate(data => {
            window.postMessage(data, '*');
        }, data);

        // 等待 ECharts 动画完成
        await page.waitForFunction(
            () => window.chartRendered === true,
            { timeout: 60000 }
        );

        const element = await page.$('#chart');
        const boundingBox = await element.boundingBox();

        if (!boundingBox) {
            throw new Error('#chart 元素未能正确加载或未设置尺寸');
        }

        await page.setViewport({
            width: Math.ceil(boundingBox.width),
            height: Math.ceil(boundingBox.height)
        });

        const screenshotBuffer = await element.screenshot();

        res.setHeader('Content-Type', 'image/png');
        
        res.send(screenshotBuffer);
    } catch (error) {
        console.error('生成图表时出错:', error);
        res.status(500).send('生成图表时出错');
    } finally {
        if (browser) {
            await browser.close();
        }
    }
});

const PORT = 3000;
app.listen(PORT, () => {
    console.log(`Puppeteer 服务运行在端口 ${PORT}`);
});

echarts代码

首先创建一个templates文件夹放在根目录下, 然后我们把所有将来要用到生成图片的echarts的html文件放在这个目录下

我们可以再官网女随便找一个echarts图片来进行生成

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>
</head>
<body>
    <div id="chart" style="width: 600px;height:400px;"></div>
    <script>
        // 使用传入的配置参数初始化 ECharts 图表
        function renderChart(option) {
            var chart = echarts.init(document.getElementById('chart'));
            chart.setOption(option);

            // 在所有动画完成后触发事件
            chart.on('finished', function () {
                console.log('ECharts animation finished');
                window.chartRendered = true;
            });
        }

        // 等待 Puppeteer 注入配置参数并渲染图表
        window.addEventListener('message', function (event) {
            renderChart(event.data);
        });
    </script>
</body>
</html>

启动服务

启动服务只需要在根目录下执行

bash 复制代码
node index.js

测试请求服务

使用postman请求:http://localhost:3000/generate-echarts

请求体:

bash 复制代码
{
  "templateName": "echart",
  "data": {
    "title": { "text": "动态 ECharts 示例" },
    "tooltip": {},
    "xAxis": { "data": ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"] },
    "yAxis": {},
    "series": [{ "name": "销量", "type": "bar", "data": [5, 20, 36, 10, 10, 20] }]
  }
}
相关推荐
10年前端老司机2 小时前
什么!纯前端也能识别图片中的文案、还支持100多个国家的语言
前端·javascript·vue.js
摸鱼仙人~2 小时前
React 性能优化实战指南:从理论到实践的完整攻略
前端·react.js·性能优化
程序员阿超的博客3 小时前
React动态渲染:如何用map循环渲染一个列表(List)
前端·react.js·前端框架
magic 2453 小时前
模拟 AJAX 提交 form 表单及请求头设置详解
前端·javascript·ajax
小小小小宇7 小时前
前端 Service Worker
前端
只喜欢赚钱的棉花没有糖8 小时前
http的缓存问题
前端·javascript·http
小小小小宇8 小时前
请求竞态问题统一封装
前端
loriloy8 小时前
前端资源帖
前端
源码超级联盟8 小时前
display的block和inline-block有什么区别
前端
GISer_Jing8 小时前
前端构建工具(Webpack\Vite\esbuild\Rspack)拆包能力深度解析
前端·webpack·node.js