【问题标题】:How do I load Google Charts in node.js?如何在 node.js 中加载谷歌图表?
【发布时间】:2020-06-25 04:43:02
【问题描述】:

当我尝试在 node.js 中加载 Google 图表时,没有任何反应。

我尝试从zombie.js 和jsdom 中的折线图文档中加载first example,但无论哪种情况,图表都不会加载。

最终目标是检索生成图表的 SVG 数据以导出为图像或 PDF。因此,如果可以使用替代方法(使用 node.js 或 PHP 的服务器端)来实现这一点,我愿意接受建议。

注意:我已经使用gChartPhp成功生成了一些图表的图像,但是这个项目的要求是嵌入版本是当前API提供的交互版本,导出版本是视觉上与嵌入式相同(显然没有交互)。

编辑:我标记了PhantomJS,因为这是我最终采用的解决方案。

对不起,缺少链接,但垃圾邮件预防机制只允许我发布 2 个。

【问题讨论】:

    标签: php node.js google-visualization phantomjs


    【解决方案1】:

    我迟到了 8 年,但我刚刚发布了一个开源项目 Google Charts Node,它在 Puppeteer 中呈现图表图像(在某种程度上是原始 PhantomJS 解决方案的继承者)。

    google-charts-node 可用作 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, {
      width: 400,
      height: 300,
    });
    

    现在您可以将此image 缓冲区保存为文件或将其作为 HTTP 响应返回,等等。

    创建它非常简单。主要的警告是:

    1. 并非所有图表都支持 getImageURI,所以当发生这种情况时,我会求助于 puppeteer 来截取屏幕截图。
    2. 很慢!但是,如果您必须使用 Google 图表作为要求,那么您真的没有其他选择。这个问题可以通过足够的云计算资源得到缓解。

    您可以在 Github project 查看完整源代码,但如果您想自己动手,这里是原始木偶流程:

    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;
    }
    

    【讨论】:

      【解决方案2】:

      这不是理想的解决方案,但我在 PhantomJS 中找到了 node.js 的替代方案来实现相同的最终目标。只需创建一个包含图表 (test.html) 的 HTML 文件,并且像 node.js 一样,创建一个包含您的代码 (test.js) 的 JS 文件。然后用 PhantomJS 运行你的 JS 文件。

      在您的 JS 文件中,将 HTML 文件作为网页打开,然后渲染它,或者将图像缓冲区保存到文件中:

      var page = require('webpage').create();
      page.open('test.html', function () {
          page.render('test.png');
          phantom.exit();
      });
      

      然后运行它:

      phantomjs test.js
      

      要动态创建图表,请创建以下 JS 文件(test2.js):

      var system = require('system');
      var page = require('webpage').create();
      page.onCallback = function(data)
      {
          page.clipRect = data.clipRect;
          page.render('test.png');
          phantom.exit();
      };
      page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js', function()
      {
          page.includeJs('https://www.google.com/jsapi', function()
          {
              page.evaluate(function(chartType, data_json, options_json)
              {
                  var div = $('<div />').attr('id', 'chart').width(900).height(500).appendTo($('body'));
                  google.load("visualization", "1",
                  {
                      packages:[chartType == 'GeoChart' ? 'geochart' : 'corechart'],
                      callback: function()
                      {
                          data_arr = $.parseJSON(data_json);
                          data = google.visualization.arrayToDataTable(data_arr);
                          options = $.parseJSON(options_json);
                          chart = new google.visualization[chartType]($(div).get(0));
                          google.visualization.events.addListener(chart, 'ready', function()
                          {
                              window.callPhantom(
                              {
                                  clipRect: $(div).get(0).getBoundingClientRect()
                              });
                          });
                          chart.draw(data, options);
                      }
                  });
              }, system.args[1], system.args[2], system.args[3]);
          });
      });
      

      然后运行它:

      phantomjs test2.js LineChart '[["Date","Steve","David","Other"],["Dec 31",8,5,3],["Jan 1",7,10,4],["Jan 2",9,4,3],["Jan 3",7,5,3]]' '{"hAxis.slantedText":true}'
      
      phantomjs test2.js PieChart '[["Employee","Calls"],["Steve",31],["David",24],["Other",13]]' '{"is3D":true}'
      
      phantomjs test2.js GeoChart '[["State","Calls"],["US-CA",7],["US-TX",5],["US-FL",4],["US-NY",8]]' '{"region":"US","resolution":"provinces"}'
      

      要从外部脚本获取图像数据,请复制 test2.js (test3.js) 并更改

      page.render('test.png');
      

      console.log(page.renderBase64('png'));
      

      然后调用它(例如来自 PHP):

      <?php
      
          $data = array(
              array("Employee", "Calls"),
              array("Steve", 31),
              array("David", 24),
              array("Other", 13)
          );
          $options = array(
              "is3D" => true
          );
          $command = "phantomjs test3.js PieChart '" . json_encode($data) . "' '" . json_encode($options) . "'";
          unset($output);
          $result = exec($command, $output);
          $base64_image = implode("\n", $output);
          $image = base64_decode($base64_image);
      
      ?>
      

      注意:回顾整个过程,我在使用 node.js 时遇到的问题可能是我没有设置回调或超时来等到图表“准备好”。

      【讨论】:

        猜你喜欢
        • 2012-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多