使用 Puppeteer 渲染 Google 个图表
Render Google Charts with Puppeteer
我正在尝试找出结合 Puppeteer 和 GoogleCharts 库以呈现条形图并导出图表的 PNG 图像的正确方法。
主要受 Puppeteer 文档启发的基本布局似乎与此类似,用于创建一个包含 canvas 元素的新页面。
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(`
<!DOCTYPE html>
<html>
<body>
<canvas id="chart" width="580" height="400"></canvas>
</body>
</html>
`);
await browser.close();
})();
我发现这个 npm 包可以与 Google 图表一起使用:https://www.npmjs.com/package/google-charts。 chart.draw
方法似乎接受一个 DOM 元素,它将在其中呈现图表。
根据这个包的文档,用法看起来很简单。
const pie_1_chart = new GoogleCharts.api.visualization.PieChart(document.getElementById('chart1'));
pie_1_chart.draw(data);
如何执行 draw 方法,以便它在 Puppeteer 页面的 #canvas
DOM 元素内呈现图表?
此外,如果您能给我一个将 page/canvas 导出为 PNG 图像的正确方法的示例,我们将不胜感激。
注意:我浏览了很多,找到了一个现有的 library/package 可以实现我想要实现的目标,但我能找到的最接近的是一个 TypeScript 包对于 Chart.JS:https://github.com/SeanSobey/ChartjsNodePuppeteer。我不熟悉 TypeScript/ES6,所以我不知道如何调整此库以使其与 Google 图表库一起使用,而不是 Chart.JS。
谢谢
我设置了一个 puppeteer 代码,它加载 Google 图表示例页面的 Iframe,然后截取 elementHandle
#chart_div
。
这比加载另一个库要快得多,也简单得多。
接下来您可以使用 div 元素创建 HTML DOM 并使用它设置 Google 图表并截取 div 元素。
const page = await browser.newPage()
page.setDefaultNavigationTimeout(0);
const goto = await page.goto('https://developers-dot-devsite-v2-prod.appspot.com/chart/interactive/docs/gallery/barchart_9a8ce4c79b8da3fa2e73bee14869e01b6f7fb5150dc7540172d60b5680259b48.frame')
const wait = await page.waitForSelector('#chart_div > div', {'visible' : true, 'timeout' : 0})
const elem = await page.$('#chart_div')
const save = await elem.screenshot({path : 'googlechart.png' })
我遇到了同样的问题并将其烘焙到一个名为 Google Charts Node 的开源库中。
这是一个用法示例:
const GoogleChartsNode = require('google-charts-node');
// Define your chart drawing function
function drawChart() {
const data = google.visualization.arrayToDataTable([
['City', '2010 Population',],
['New York City, NY', 8175000],
['Los Angeles, CA', 3792000],
['Chicago, IL', 2695000],
['Houston, TX', 2099000],
['Philadelphia, PA', 1526000]
]);
const options = {
title: 'Population of Largest U.S. Cities',
chartArea: {width: '50%'},
hAxis: {
title: 'Total Population',
minValue: 0
},
vAxis: {
title: 'City'
}
};
const chart = new google.visualization.BarChart(container);
chart.draw(data, options);
}
// Render the chart to image
const image = await GoogleChartsNode.render(drawChart, {
width: 400,
height: 300,
});
render
方法 returns 包含此图像的缓冲区:
它在 NPM 上可用 google-charts-node。
关于使用 Puppeteer 渲染的一般问题,我发现它相当简单。我尝试尽可能使用图表提供的方法 getImageURI
,但并非所有图表都支持它。在这种情况下,我使用 Puppeteer 截屏。
这是基本逻辑(也可以查看完整的 source code):
async function render() {
// Puppeteer setup
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Add the chart
await page.setContent(`...Insert your Google Charts code here...`);
// Use getImageURI if available (not all charts support)
const imageBase64 = await page.evaluate(() => {
if (!window.chart || typeof window.chart.getImageURI === 'undefined') {
return null;
}
return window.chart.getImageURI();
});
let buf;
if (imageBase64) {
buf = Buffer.from(imageBase64.slice('data:image/png;base64,'.length), 'base64');
} else {
// getImageURI was not available - take a screenshot using puppeteer
const elt = await page.$('#chart_div');
buf = await elt.screenshot();
}
await browser.close();
return buf;
}
我已经使用下面的代码行在 node.js 应用程序中设置了 puppeteer。在 pdf 文件中显示图表工作正常。
对我来说 defaultViewport: null 和 args: ['--window-size=1920,1080'] 的组合让我全屏显示适合屏幕大小的视图,图表显示适当的宽度应用中显示:
const browser = await puppeteer.launch({
headless: true,
defaultViewport: null,
args: [
'--window-size=1366,768',
'--no-sandbox',
'--disable-setuid-sandbox',
],
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(0);
await page.goto(reportUrl, {
waitUntil: ['load', 'domcontentloaded', 'networkidle0'],
});
这是我使用 PDF 文件中的图表的代码,解决了获取 PDF 文件中图表的完整宽度的问题,类似于应用程序视图
defaultViewport 的选项:null 和 args:['--window-size=1920,1080'] 在应用程序中对我有用,并提供完整视图以创建图表的 pdf
const browser = await puppeteer.launch({
headless: true,
defaultViewport: null,
args: [
'--window-size=1366,768'
],
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(0);
await page.goto(reportUrl, {
waitUntil: ['load', 'domcontentloaded', 'networkidle0'],
});
我正在尝试找出结合 Puppeteer 和 GoogleCharts 库以呈现条形图并导出图表的 PNG 图像的正确方法。
主要受 Puppeteer 文档启发的基本布局似乎与此类似,用于创建一个包含 canvas 元素的新页面。
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(`
<!DOCTYPE html>
<html>
<body>
<canvas id="chart" width="580" height="400"></canvas>
</body>
</html>
`);
await browser.close();
})();
我发现这个 npm 包可以与 Google 图表一起使用:https://www.npmjs.com/package/google-charts。 chart.draw
方法似乎接受一个 DOM 元素,它将在其中呈现图表。
根据这个包的文档,用法看起来很简单。
const pie_1_chart = new GoogleCharts.api.visualization.PieChart(document.getElementById('chart1'));
pie_1_chart.draw(data);
如何执行 draw 方法,以便它在 Puppeteer 页面的 #canvas
DOM 元素内呈现图表?
此外,如果您能给我一个将 page/canvas 导出为 PNG 图像的正确方法的示例,我们将不胜感激。
注意:我浏览了很多,找到了一个现有的 library/package 可以实现我想要实现的目标,但我能找到的最接近的是一个 TypeScript 包对于 Chart.JS:https://github.com/SeanSobey/ChartjsNodePuppeteer。我不熟悉 TypeScript/ES6,所以我不知道如何调整此库以使其与 Google 图表库一起使用,而不是 Chart.JS。
谢谢
我设置了一个 puppeteer 代码,它加载 Google 图表示例页面的 Iframe,然后截取 elementHandle
#chart_div
。
这比加载另一个库要快得多,也简单得多。
接下来您可以使用 div 元素创建 HTML DOM 并使用它设置 Google 图表并截取 div 元素。
const page = await browser.newPage()
page.setDefaultNavigationTimeout(0);
const goto = await page.goto('https://developers-dot-devsite-v2-prod.appspot.com/chart/interactive/docs/gallery/barchart_9a8ce4c79b8da3fa2e73bee14869e01b6f7fb5150dc7540172d60b5680259b48.frame')
const wait = await page.waitForSelector('#chart_div > div', {'visible' : true, 'timeout' : 0})
const elem = await page.$('#chart_div')
const save = await elem.screenshot({path : 'googlechart.png' })
我遇到了同样的问题并将其烘焙到一个名为 Google Charts Node 的开源库中。
这是一个用法示例:
const GoogleChartsNode = require('google-charts-node');
// Define your chart drawing function
function drawChart() {
const data = google.visualization.arrayToDataTable([
['City', '2010 Population',],
['New York City, NY', 8175000],
['Los Angeles, CA', 3792000],
['Chicago, IL', 2695000],
['Houston, TX', 2099000],
['Philadelphia, PA', 1526000]
]);
const options = {
title: 'Population of Largest U.S. Cities',
chartArea: {width: '50%'},
hAxis: {
title: 'Total Population',
minValue: 0
},
vAxis: {
title: 'City'
}
};
const chart = new google.visualization.BarChart(container);
chart.draw(data, options);
}
// Render the chart to image
const image = await GoogleChartsNode.render(drawChart, {
width: 400,
height: 300,
});
render
方法 returns 包含此图像的缓冲区:
它在 NPM 上可用 google-charts-node。
关于使用 Puppeteer 渲染的一般问题,我发现它相当简单。我尝试尽可能使用图表提供的方法 getImageURI
,但并非所有图表都支持它。在这种情况下,我使用 Puppeteer 截屏。
这是基本逻辑(也可以查看完整的 source code):
async function render() {
// Puppeteer setup
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Add the chart
await page.setContent(`...Insert your Google Charts code here...`);
// Use getImageURI if available (not all charts support)
const imageBase64 = await page.evaluate(() => {
if (!window.chart || typeof window.chart.getImageURI === 'undefined') {
return null;
}
return window.chart.getImageURI();
});
let buf;
if (imageBase64) {
buf = Buffer.from(imageBase64.slice('data:image/png;base64,'.length), 'base64');
} else {
// getImageURI was not available - take a screenshot using puppeteer
const elt = await page.$('#chart_div');
buf = await elt.screenshot();
}
await browser.close();
return buf;
}
我已经使用下面的代码行在 node.js 应用程序中设置了 puppeteer。在 pdf 文件中显示图表工作正常。
对我来说 defaultViewport: null 和 args: ['--window-size=1920,1080'] 的组合让我全屏显示适合屏幕大小的视图,图表显示适当的宽度应用中显示:
const browser = await puppeteer.launch({
headless: true,
defaultViewport: null,
args: [
'--window-size=1366,768',
'--no-sandbox',
'--disable-setuid-sandbox',
],
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(0);
await page.goto(reportUrl, {
waitUntil: ['load', 'domcontentloaded', 'networkidle0'],
});
这是我使用 PDF 文件中的图表的代码,解决了获取 PDF 文件中图表的完整宽度的问题,类似于应用程序视图
defaultViewport 的选项:null 和 args:['--window-size=1920,1080'] 在应用程序中对我有用,并提供完整视图以创建图表的 pdf
const browser = await puppeteer.launch({
headless: true,
defaultViewport: null,
args: [
'--window-size=1366,768'
],
});
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(0);
await page.goto(reportUrl, {
waitUntil: ['load', 'domcontentloaded', 'networkidle0'],
});