无浏览器Node.js环境下,如何生成柱状图并插入PDF?
问题描述
我有一个使用PDF生成器的Node.js项目,需要在其中插入柱状图,但项目运行在无桌面环境的服务器上。请问有没有无需依赖Web浏览器,就能在Node.js运行时生成柱状图图片并插入PDF的库或方法?
我目前使用Puppeteer生成PDF,但Chart.js库无法渲染canvas,示例代码如下:
await page.setContent(`<!DOCTYPE html> <html><body> <canvas id="chart"></canvas> <script> const ctx = document.getElementById('chart'); new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); </script> </body></html>`, { waitUntil: 'domcontentloaded' }); await page.addScriptTag({ url: 'https://cdn.jsdelivr.net/npm/chart.js' })
结果显示空白页面,因此我希望找到更好的方案直接生成图片并插入。
我还尝试了以下代码:
await page.setContent(`<!DOCTYPE html> <html><body> <canvas id="chart"></canvas> </body></html>`, { waitUntil: [ 'load', 'networkidle0' ] }); await page.addScriptTag({ url: 'https://cdn.jsdelivr.net/npm/chart.js' }); await page.addScriptTag({ content: ` const ctx = document.getElementById('chart'); new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); });
解决方案
方案一:node-canvas + Chart.js(无浏览器依赖)
直接在Node.js环境生成Canvas图片,完全不需要浏览器支持,适合无桌面环境的服务器。
- 安装依赖:
npm install canvas chart.js
- 示例代码:
const { createCanvas } = require('canvas'); const Chart = require('chart.js/auto'); const fs = require('fs'); const PDFDocument = require('pdfkit'); // 创建固定尺寸的画布 const canvas = createCanvas(800, 600); const ctx = canvas.getContext('2d'); // 生成柱状图 new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], borderWidth: 1, backgroundColor: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff', '#ff9f40'] }] }, options: { responsive: false, // 固定画布尺寸,关闭响应式 scales: { y: { beginAtZero: true } } } }); // 将画布转为PNG Buffer const chartBuffer = canvas.toBuffer('image/png'); // 插入到PDF const doc = new PDFDocument(); doc.pipe(fs.createWriteStream('output.pdf')); // 设置图片在PDF中的位置和宽度 doc.image(chartBuffer, 50, 50, { width: 600 }); doc.end();
方案二:修复Puppeteer + Chart.js的渲染问题
你的代码空白是因为两个问题:Canvas未指定尺寸、Chart.js加载和执行顺序错误。修改后的代码如下:
await page.setContent(`<!DOCTYPE html> <html><body> <!-- 必须指定Canvas的宽高 --> <canvas id="chart" width="800" height="600"></canvas> </body></html>`, { waitUntil: 'networkidle0' }); // 先加载Chart.js库 await page.addScriptTag({ url: 'https://cdn.jsdelivr.net/npm/chart.js' }); // 等待库加载完成后,执行图表渲染逻辑 await page.evaluate(() => { const ctx = document.getElementById('chart').getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); }); // 等待图表渲染完成(可根据实际情况调整延迟时间) await page.waitForTimeout(1000); // 生成PDF await page.pdf({ path: 'output.pdf', format: 'A4' });
方案三:使用chartjs-node-canvas(封装好的工具)
这是专门为Node.js环境封装的Chart.js工具,简化了node-canvas的配置步骤。
- 安装依赖:
npm install chartjs-node-canvas pdfkit
- 示例代码:
const { ChartJSNodeCanvas } = require('chartjs-node-canvas'); const fs = require('fs'); const PDFDocument = require('pdfkit'); // 定义图表尺寸 const chartWidth = 800; const chartHeight = 600; const chartCanvas = new ChartJSNodeCanvas({ width: chartWidth, height: chartHeight }); (async () => { // 生成图表图片Buffer const chartBuffer = await chartCanvas.renderToBuffer({ type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); // 插入到PDF const doc = new PDFDocument(); doc.pipe(fs.createWriteStream('output.pdf')); doc.image(chartBuffer, 50, 50, { width: 600 }); doc.end(); })();
内容的提问来源于stack exchange,提问作者e-info128
相关产品推荐
相关产品推荐

