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

efzxgjgh  于 2023-10-17  发布在  Node.js
关注(0)|答案(1)|浏览(152)

我正在寻找一些关于在NodeJS控制台应用程序中生成D3 js图表并将图表保存为PNG或JPG的帮助。
我的用例涉及一个自动化任务,该任务每两周运行一次,并循环遍历结果列表,向客户生成电子邮件通知。在这封电子邮件中,我想包括使用D3 js生成的各种图表。要将D3 js图表嵌入到我们的客户电子邮件中,我们需要将D3 js图表以PNG/JPG格式保存到磁盘/流中,以便将图像上传到我们的SMTP提供程序。图表和数据是动态的,对每个客户来说都是唯一的,因此需要在向客户发送电子邮件之前立即生成图表。
我看到过SaaS产品通过API生成D3 js图表,但这被管理层排除了(:shrug:)。
我在网上找到的非SaaS D3 js示例都是围绕着将图表嵌入到网页中。我们可不想这么做。
我被从哪里开始卡住了,这就是为什么这篇文章中没有代码示例。任何帮助将不胜感激。

vfh0ocws

vfh0ocws1#

d3.js操作HTML DOM。因此,它需要存在于浏览器中的DOM JavaScript API。
如果你想在Node.js中使用d3.js,你可以使用像jsdom这样的库来模拟DOM及其API。
然后,您可以使用sharp包将SVG转换为PNG或任何图像文件。

  1. // use jsdom to emulate the browser DOM
  2. const jsdom = require('jsdom');
  3. const { JSDOM } = jsdom;
  4. // for saving the SVG image to disk
  5. const fs = require('fs');
  6. // for converting SVG to an image
  7. const sharp = require('sharp');
  8. /** renders a D3.js generated SVG DOM into an image file */
  9. const renderD3ImageFile = async (data) => {
  10. /************************************************/
  11. /************** Emulating the DOM ***************/
  12. /************************************************/
  13. // emulate the DOM structure
  14. const dom = new JSDOM('<!DOCTYPE html><body><svg id="bar-chart"></svg></body></html>')
  15. // get the SVG container element
  16. const svgElement = dom.window.document.getElementById("bar-chart");
  17. /************************************************/
  18. /****************** D3 Drawing ******************/
  19. /************************************************/
  20. /* Import the d3 library
  21. If your node app is of 'module' type, you can simply use the syntax "import * as d3 from 'd3'"
  22. Earlier versions of d3 can be loaded using commonJs.
  23. */
  24. const d3 = await import('d3');
  25. // select the SVG element using D3.js
  26. const svg = d3.select(svgElement)
  27. // not sure if this is necessary
  28. .attr('xmlns', "http://www.w3.org/2000/svg");
  29. const svgWidth = 1080;
  30. const svgHeight = 300;
  31. /* Sizing the svg image
  32. Since our DOM is emulated, we cannot enquire any sizing information from it.
  33. We can either size the SVG by (1) providing fixed height/width values or (2) by using the viewBox attribute.
  34. The following code uses the viewBox attributes
  35. */
  36. svg.attr('width', `${svgWidth}px`)
  37. .attr('height', `${svgHeight}px`);
  38. // any kind of D3.js magic
  39. const x = d3.scaleLinear([0, 100], [0, svgWidth]);
  40. const coreGroup = svg.append('g').attr('class', 'core-group');
  41. const barHeight = 50;
  42. const barTopMargin = 10;
  43. const someRandomBars = coreGroup.selectAll('g.bar')
  44. .data([10, 75, 100, 24, 55])
  45. .enter()
  46. .append('g')
  47. .attr('class', 'bar')
  48. .attr('transform', (d,i) => `translate(0 ${i * (barHeight + barTopMargin)})`);
  49. someRandomBars.append('rect')
  50. .attr('x', 0).attr('y', 0)
  51. .attr('width', (d) => {
  52. return x(d) + 'px';
  53. })
  54. .attr('height', `${barHeight}px`)
  55. // all styling has to be done inline
  56. .attr('fill', 'purple');
  57. // the html of the element is our SVG image
  58. const svgAsText = svgElement.outerHTML;
  59. // save as SVG (for debugging)
  60. fs.writeFileSync('output.svg', svgAsText);
  61. // save as raster image file
  62. const svgImageBuffer = Buffer.from(svgAsText);
  63. await sharp(svgImageBuffer)
  64. .png()
  65. .toFile("output.png");
  66. };
  67. // trigger the render promise
  68. renderD3ImageFile()
  69. .then(() => console.log('picture rendered!'))
  70. .catch(error => console.error(error));

下面的代码创建了一个简单的条形图PNG图像:

常见问题与思考

在Node.js中加载d3.js

最新版本的d3.js是一个ES模块。因此,除非你的Node.js应用是"type": "module",否则你必须通过import('d3') promise加载它。许多示例都使用CommonJS和早期版本的d3。

调整图片大小(& elements)

有两种方法可以调整SVG图形的大小:
1.使用静态widthheight属性(如上面的示例)。
1.使用viewBoxpreserveAspectRatio属性。我喜欢使用这个,因为它提供了更多的灵活性,在未来的位置的形象。
重要的是要知道DOM只是模拟的。也就是说,查询大小(getBBox())的DOM函数不存在。

HTML vs Image渲染

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

展开查看全部

相关问题