在 NodeJS 控制台应用程序中生成 D3js 图表

问题描述 投票:0回答:1

我正在寻求一些有关在 NodeJS 控制台应用程序中生成 D3js 图表并将图表以 PNG 或 JPG 格式保存到磁盘的帮助。

我的用例涉及一个自动化任务,该任务每两周运行一次并循环遍历结果列表,向客户生成电子邮件通知。在那封电子邮件中,我想包含使用 D3js 生成的各种图表。要将 D3js 图表嵌入到我们的客户电子邮件中,我们需要将 D3js 图表以 PNG/JPG 格式保存到磁盘/流中,以将图像上传到我们的 SMTP 提供商。图表和数据对于每个客户来说都是动态且唯一的,因此需要在将电子邮件发送给客户之前立即生成图表。

我见过 SaaS 产品可以通过 API 生成 D3js 图表,但管理层已经排除了这种可能性 (:shrug:)。

我在网上找到的非 SaaS D3js 示例主要围绕将图表嵌入到网页中。这不是我们想要做的。

我不知道从哪里开始,这就是为什么本文中没有代码示例的原因。任何帮助将不胜感激。

node.js d3.js
1个回答
0
投票

d3.js 操作 HTML DOM。因此,它需要浏览器中存在的 DOM JavaScript API。

如果你想在 Node.js 中使用 d3.js,你可以使用像

jsdom
这样的库来模拟 DOM 及其 API。

然后您可以使用

sharp
包将 SVG 转换为 PNG 或任何图像文件。

// use jsdom to emulate the browser DOM
const jsdom = require('jsdom');
const { JSDOM } = jsdom;

// for saving the SVG image to disk
const fs = require('fs');
// for converting SVG to an image
const sharp = require('sharp');

/** renders a D3.js generated SVG DOM into an image file */
const renderD3ImageFile = async (data) => {
  /************************************************/
  /************** Emulating the DOM ***************/
  /************************************************/

  // emulate the DOM structure
  const dom = new JSDOM('<!DOCTYPE html><body><svg id="bar-chart"></svg></body></html>')
  // get the SVG container element
  const svgElement = dom.window.document.getElementById("bar-chart");

  /************************************************/
  /****************** D3 Drawing ******************/
  /************************************************/

  /* Import the d3 library
  If your node app is of 'module' type, you can simply use the syntax "import * as d3 from 'd3'"
  Earlier versions of d3 can be loaded using commonJs.
  */
  const d3 = await import('d3');

  // select the SVG element using D3.js
  const svg = d3.select(svgElement)
    // not sure if this is necessary
    .attr('xmlns', "http://www.w3.org/2000/svg");

  const svgWidth = 1080;
  const svgHeight = 300;

  /* Sizing the svg image
  Since our DOM is emulated, we cannot enquire any sizing information from it.
  We can either size the SVG by (1) providing fixed height/width values or (2) by using the viewBox attribute.

  The following code uses the viewBox attributes
   */
  svg.attr('width', `${svgWidth}px`)
    .attr('height', `${svgHeight}px`);

  // any kind of D3.js magic

  const x = d3.scaleLinear([0, 100], [0, svgWidth]);
  const coreGroup = svg.append('g').attr('class', 'core-group');
  const barHeight = 50;
  const barTopMargin = 10;
  const someRandomBars = coreGroup.selectAll('g.bar')
    .data([10, 75, 100, 24, 55])
    .enter()
    .append('g')
    .attr('class', 'bar')
    .attr('transform', (d,i) => `translate(0 ${i * (barHeight + barTopMargin)})`);
  someRandomBars.append('rect')
    .attr('x', 0).attr('y', 0)
    .attr('width', (d) => {
      return x(d) + 'px';
    })
    .attr('height', `${barHeight}px`)
    // all styling has to be done inline
    .attr('fill', 'purple');

  // the html of the element is our SVG image
  const svgAsText = svgElement.outerHTML;

  // save as SVG (for debugging)
  fs.writeFileSync('output.svg', svgAsText);

  // save as raster image file
  const svgImageBuffer = Buffer.from(svgAsText);
  await sharp(svgImageBuffer)
    .png()
    .toFile("output.png");
};

// trigger the render promise
renderD3ImageFile()
  .then(() => console.log('picture rendered!'))
  .catch(error => console.error(error));

此代码创建一个简单的条形图 PNG 图像:

常见的挑战和想法

在 Node.js 中加载 d3.js

最新版本的 d3.js 是一个 ES 模块。因此,除非您的 Node.js 应用程序要

"type": "module"
,否则您必须通过
import('d3')
承诺加载它。 许多示例都将 CommonJS 与早期版本的 d3 结合使用。

调整图像和元素的大小

有两种方法可以调整 SVG 绘图的大小:

  1. 使用静态
    width
    height
    属性(如上例所示)。
  2. viewBox
    preserveAspectRatio
    属性一起使用。我喜欢使用它,因为它为将来的图像放置提供了更多的灵活性。

重要的是要知道 DOM 只是模拟的。 IE。查询大小的 DOM 函数 (

getBBox()
) 不存在。

HTML 渲染与图像渲染

在为 HTML 渲染 SVG 时,我们可以(并且应该)使用 CSS 样式。在 Node.js 中渲染 SVG 时,我们必须内联部署所有样式。 当尝试在客户端和服务器端之间共享 d3.js 代码时,这可能是一个问题。

© www.soinside.com 2019 - 2024. All rights reserved.