简体   繁体   English

生成服务器端谷歌图表作为图像

[英]generate server-side google charts as images

I've just started using the (new) Google Charts api and its pretty cool.我刚刚开始使用(新的)Google Charts api,它非常酷。 I'm successfully creating charts using this api.我正在使用这个 api 成功创建图表。

I have a throughput challenge however.但是,我有吞吐量挑战。 In my application I generate three charts from real-time data I'm pulling down from NOAA.在我的应用程序中,我根据从 NOAA 提取的实时数据生成三个图表。 The time it takes to get the data, massage it into chart form and then draw the chart client-side is an intolerably slow user experience.获取数据,将其整理成图表形式,然后在客户端绘制图表所花费的时间是令人无法忍受的缓慢用户体验。

So my thought was to generate the chart periodically (every 15-30 min) on the (hosted) server and then just serve up an image of the most recent to visitors.所以我的想法是在(托管)服务器上定期(每 15-30 分钟)生成图表,然后向访问者提供最新的图像。

I looked at phantomjs (as recommended in this post ), but it looks like its an .exe file is used and I can't upload that to my shared host.我看着phantomjs(在推荐这个帖子),但它看起来像它的.exe文件使用,我不能上传到我的共享主机。

There's also this thread for a proprietary solution (Highcharts), but I want to explore open source alternatives first before going down the Highcharts path.还有这个线程用于专有解决方案 (Highcharts),但我想在沿着 Highcharts 路径之前先探索开源替代方案。

Other solutions focus on allowing the user to save a rendered chart as an image, but my goal is to never render the chart in the browser or have any server load other than including an image at the time of page request.其他解决方案侧重于允许用户将呈现的图表保存为图像,但我的目标是永远不要在浏览器中呈现图表或在页面请求时包含图像之外的任何服务器负载。

I just haven't seen anything that handles dynamically generated charts that are "automatically" converted into an image that is "automatically" served when the page is rendered.我只是没有看到任何处理动态生成的图表的东西,这些图表“自动”转换为在呈现页面时“自动”提供的图像。

In summary, here are the three pieces I am trying to cobble together:总而言之,这是我试图拼凑起来的三个部分:

1) pulling data from a third party (NOAA in this case) and rendering data as a Google Chart (done, no issues here) 2) converting each rendered chart into an image automatically, server side and creating image urls 3) sticking the image URL of the chart (which will be refreshed frequently) into the html of the web-page before rendering (via php) 1)从第三方(在这种情况下为 NOAA)提取数据并将数据呈现为谷歌图表(完成,这里没有问题)2)将每个呈现的图表自动转换为图像,服务器端并创建图像网址 3)粘贴图像图表的 URL(会经常刷新)在呈现之前(通过 php)到网页的 html 中

PS its ok to have a static url for each chart image...I'm not creating an archive of images... PS 可以为每个图表图像设置一个静态 url ......我不是在创建图像存档......

Any recommendations?有什么建议吗? Am I missing something?我错过了什么吗?

Use Watir to load the web page and save the images.使用Watir加载网页并保存图像。 Watir is a Ruby-based test platform aimed at testing web pages. Watir 是一个基于 Ruby 的测试平台,旨在测试网页。 I would do the following.我会做以下事情。

  1. Create a web page that renders the charts.创建一个呈现图表的网页。 It would not be for public use, only for generating the chart images.它不会供公众使用,仅用于生成图表图像。
  2. Add Javascript that calls getImageURI() for each chart to get the PNG data.添加为每个图表调用 getImageURI() 以获取 PNG 数据的 Javascript。
  3. Use Ajax to call a PHP script on the server.使用 Ajax 在服务器上调用 PHP 脚本。 Pass in the PNG data and save it to a file.传入 PNG 数据并将其保存到文件中。
  4. Write a script in Watir that simply opens a browser and loads your web page.在 Watir 中编写一个脚本,只需打开浏览器并加载您的网页。
  5. Schedule the Watir script to run as often as you desire.安排 Watir 脚本按您需要的频率运行。

The Watir script can run on any local computer (PC or Mac) or even on a server. Watir 脚本可以在任何本地计算机(PC 或 Mac)甚至服务器上运行。

Here's Javascript to send the PNG data to a PHP script via Ajax.这是通过 Ajax 将 PNG 数据发送到 PHP 脚本的 Javascript。 It is just the snippet that gets the image data and sends it, not a complete solution.它只是获取图像数据并发送它的片段,而不是完整的解决方案。

// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.PieChart(chartDiv);
// Wait for the chart to finish drawing before calling the getImageURI() method.
google.visualization.events.addListener(chart, 'ready', function () {
    pieDone=1;
    piePNG=chart.getImageURI();
    saveChartPNGs(piePNG); 
});
chart.draw(data, options);

function saveChartPNGs(png)
{
  var jsonSavePNG = $.ajax({
    type: "POST",
    url: pngSaveUrl,
    dataType:"json",
    data: 'png=' + png
  }).done();
}

This PHP code processes the Ajax call and saves the file.此 PHP 代码处理 Ajax 调用并保存文件。

if (isset($_REQUEST['png']))
{
    // Remove header string
    $data=str_replace('data:image/png;base64,','',$_REQUEST['png']);
    // Restore data to original format; convert space to '+'
    $data=str_replace(' ','+',$data);
    // Save PNG file
    $outFile=DOC_ROOT.'/atest.png';
    // Decode base 64 before saving
    $fres=file_put_contents($outFile, base64_decode($data));
}

On your local computer, the Watir script (actually written in Ruby) is simple.在您的本地计算机上,Watir 脚本(实际上是用 Ruby 编写的)很简单。

# Load watir
require 'watir-webdriver'
require "watir-webdriver/extensions/alerts"

# Launch the browser; common choices: chrome, firefox, ie.
# Headless browsers are available.
browser = Watir::Browser.new :chrome # chrome browser window

# Load the web page
browser.goto 'http://domain.net/page/'

To fully automate the Watir side I would write the chart rendering web page to load a new page when it has finished saving the files.为了使 Watir 端完全自动化,我将编写图表渲染网页,以便在完成保存文件后加载新页面。 You can have Watir check for that page in the browser and then exit until it executes again.您可以让 Watir 在浏览器中检查该页面,然后退出,直到它再次执行。

If you can arrange to install Ruby, Watir and a browser on your server, then you can automate this entire scenario with a cron job.如果您可以安排在您的服务器上安装 Ruby、Watir 和浏览器,那么您可以使用 cron 作业自动化整个场景。

I've just released a relevant open-source project Google Charts Node that renders chart images in Puppeteer, a headless Chromium browser.我刚刚发布了一个相关的开源项目Google Charts Node ,它在 Puppeteer(一个无头 Chromium 浏览器)中呈现图表图像。

It can be used either as an NPM library or as a web service.它既可以用作NPM 库,也可以用作 Web 服务。 Here's an example of using the NPM library:这是使用 NPM 库的示例:

const GoogleChartsNode = require('google-charts-node');

function drawChart() {
  // Set up your chart here, just like in the browser
  // ...

  const chart = new google.visualization.BarChart(container);
  chart.draw(data, options);
}

// Render the chart to image
const image = await GoogleChartsNode.render(drawChart);

Your question was tagged PHP, so I will note that it's also available as a hosted web service that can be used in any language.你的问题被标记为 PHP,所以我会注意到它也可以作为可以用任何语言使用的托管 Web 服务。 You can read more here .您可以在此处阅读更多内容。

For example:例如:

// Generate the image
$url = 'https://quickchart.io/google-charts/render';
$data = array(
  'width' => 600,
  'height' => 300,
  'packages' => array('gannt'),
  'code' => 'function drawChart() {...}'
);

$postdata = json_encode($data);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
curl_close($ch);

// Write it to file
$fp = fopen('/tmp/image.png','x');
fwrite($fp, $raw);
fclose($fp);

Now you can save this image buffer as a file or return it as an HTTP response, etc.现在您可以将此image缓冲区保存为文件或将其作为 HTTP 响应等返回。

The main caveats are:主要的注意事项是:

  1. Not all charts support getImageURI, so the library makes puppeteer take a screenshot when this happens.并非所有图表都支持 getImageURI,因此该库会在发生这种情况时让 puppeteer 截取屏幕截图。
  2. It's slow!很慢! But if you must use Google Charts as a requirement, you don't really have an alternative.但是,如果您必须使用 Google Charts 作为要求,那么您真的别无选择。 If you're able to switch chart libraries, I recommend an open format like Chart.js via QuickChart .如果您能够切换图表库,我推荐通过QuickChart 使用像 Chart.js 这样的开放格式。

You can view the full source for generating server-side Google Charts at the Github project .您可以在Github 项目 中查看生成服务器端 Google Charts 的完整源代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM