实现node端渲染图表的简单方案

这个题目有点小,本篇博客真正谈论的应该是服务端生成图表的简单方案,这里面有两个关键字:服务端 & 简单,我们知道基于js有很多的图表库,知名的如D3、echarts 、highcharts等等,对于做数据可视化方向的同学可能自己都做过此类chart的研发,无论从零构建还是使用已有的轮子,基本上都是基于js在做,因为大部分数据可视化产品都是to B的产品。

但是有些场景下,我们还是会需要服务端的渲染结果的,比如,需要给用户发送订阅邮件,邮件中包含了图表类展示,我们知道邮件内容可以支持html,但是只能支持最基本的html,图表类内容只能以图片资源的方式嵌入进去,由于图表是动态内容,所以需要我们在发送邮件之前根据用户特性内容去动态生成,这种情况下就会有对应的需要了;另外如果你的产品需要和类似slack这样的app 集成,做dashboard展示,也同样需要在服务端生成图表。

请注意服务端生成图表和编写服务端代码生成图表的细微区别,服务端编写代码生成图表并不一定是在服务端渲染图表,有可能只是是对客户端js的一种封装而已.

常规思路

  • 图表渲染的结果当前主要有两种(canvas绘制和svg渲染),以svg渲染为例来说明

svg本质上是xml,可以看到基于svg生成的图表其实就是生成一大坨的xml,如果服务端熟悉生成svg(xml)的规则,其实在服务端完全可以生成对应的xml(即svg图片),这种思路虽然没有问题,但是实现起来有些复杂,尤其在使用第三方chart 库的情况下,每种chart 对应的svg规则可能不同,如果官方没有提供对应服务端渲染方案,那么写起来还是比较费劲的。

  • 借用浏览器渲染

在highcharts的官网可以看到不同平台的服务端导出实现,highcharts渲染后支持导出图片(svg、png、jpeg)以及pdf;默认情况下,点击导出的时候客户端会向highcharts服务器发送请求,然后服务器生成图片,响应到前端下载下来,但是这种并非是服务端渲染,而是前端发送渲染好的svg(xml)到服务器,服务端转换svg内容成图片文件,但是这种方式的前提是在浏览器端渲染完毕,服务端根据渲染结果做一些转换工作而已。

常规思路微调整

借用常规思路,我们了解到,在我们不熟悉chart库生成图表规则的前提下,我们并没有特别简单的方式来构建svg或者canvas图表,但是如果我们能在服务端直接把渲染的结果截图保存下来也基本实现了我们的方案,但是渲染chart最方便的方式是通过浏览器,此时我们便可以借用headless浏览器来实现,puppeteer正是google headless浏览器的上层node api,通过node 可以操控浏览器,node和浏览器能在同一个编程环境中,让我们在服务端借用浏览器成为一个很好思路。

要实现这么一个库,并且简单好用,那么就要保持和原chart库同样的配置,对于实现的消费者来说,最简单的调用应该就是render(options) ,options为所用第三方chart库的配置项,render方法是node端方法,图表需要浏览器渲染,我们需要一种机制在调用render方法是传递的options参数,传递给浏览器,在浏览器端拿到对应的参数进行渲染,所以基本实现步骤如下:

  1. 传递参数到node层render函数中

  2. 接收到render中option参数传递给浏览器的window对象

  3. 浏览器运行时从window对象中获取options渲染对应的结果

  4. 执行截图操作,保存渲染结果

可以用如下伪代码表示:

const puppeteer =require('puppeteer');

const render= async (options)=>{

    //创建浏览器实例
const browser = await puppeteer.launch({
args:['--no-sandbox']
});
//创建page对象
const page = await browser.newPage();
//设置page内容
await page.setContent(`
//省略部分代码
<div id="container" style="width:600px;hight=400px"></div>
...
`); //传递options对象到evaluate函数中,挂载到window对象的全局属性中
await page.evaluate((options)={
window.chart={
options
}
},options); //这里以百度echarts为例说明 ,注入echarts库到页面
await page.addScriptTag({
url:'https://cdnxxx.echarts库'
}) //echarts 初始化脚本注入页面
await page.addScriptTag({
content:`
(function (window) {
let option =window.chart.options; //浏览器环境下获取window对象中chart的配置项进行初始化
var myChart = window.echarts.init(document.getElementById('container'), null, {
renderer: 'svg'
});
myChart.setOption(option);
})(this); `
}); let $el = await page.$('#container');
let buffer = await $el.screenshot({
type: 'png',
path:'xxx.png'
}); await page.close();
await browser.close(); } //使用方法
let options = {
...// echarts 各种配置
} render(options);

上述代码可能没办法正常运行(毕竟只是伪代码),但是基本上把文字描述的步骤完整的表达了出来。对上面api不太了解的同学 点击这里

代码完善

上面的伪代码中,主要有两个变化点,1、第三方库 2、初始化脚本。

如果把上述两个变化点能封装起来,其实我们是理论上可以兼容所有charts的node端渲染的,只要提供了第三方库脚本和自定义的初始化脚本,不仅仅是chart,其它的任何内容都可以做到,只是需要写得初始化脚本是否复杂而已,这个需要根据具体需要均衡,毕竟没有银弹。

在上面思路的基础上,我抽象了一个node模块node-charts,内置了echart和highcharts的初始化脚本并支持外部扩展,使用方式如下:

npm install --save node-charts
const fs = require('fs');
const NodeCharts = require('node-charts');
let nc = new NodeCharts(); let option = {
//第三方chart 配置项
} //监听全局异常事件
nc.on('error',(err)=>{
console.log(err);
}); nc.render(option,(err,data)=>{
fs.writeFileSync('test.png',data);
},{
type:'echarts' //所用的第三方库标识,内置highcharts 和echarts两种默认为echarts,可通过根目录创建node.config.js文件配置 外部chart
})

源码见 https://github.com/JerrZhang/node-charts 欢迎issue & star.

总结

这种思路写起来较为简单,但是也有一定的不足,首先限于puppeteer的限制,截图只支持两种png 、jpeg,其它格式当前版本(1.4.0)暂时不支持

实现node端渲染图表的简单方案的更多相关文章

  1. 服务端渲染和nuxt简单介绍

    概述 最近研究了一下服务端渲染,有一些心得,记录下来供以后开发时参考,相信对其他人也有用. 参考资料: Vue SSR指南 nuxt.js官网 服务端渲染介绍 服务端渲染简单来说,就是分别对项目用we ...

  2. 实例PK(Vue服务端渲染 VS Vue浏览器端渲染)

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  3. Vue服务端渲染和Vue浏览器端渲染的性能对比

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  4. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十五║初探SSR服务端渲染(个人博客二)

    缘起 时间真快,现在已经是这个系列教程的下半部 Vue 第 12 篇了,昨天我也简单思考了下,可能明天再来一篇,Vue 就基本告一段落了,因为什么呢,这里给大家说个题外话,当时写博文的时候,只是想给大 ...

  5. Vue服务端渲染 VS Vue浏览器端渲染)

    Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...

  6. Headless Chrome:服务端渲染JS站点的一个方案【上篇】【翻译】

    原文链接:https://developers.google.com/web/tools/puppeteer/articles/ssr 注:由于英文水平有限,没有逐字翻译,可以选择直接阅读原文 tip ...

  7. vue服务端渲染简单入门实例

    想到要学习vue-ssr的同学,自不必多说,一定是熟悉了vue,并且多多少少做过几个项目.然后学习vue服务端渲染无非解决首屏渲染的白屏问题以及SEO友好. 话不多说,笔者也是研究多日才搞明白这个服务 ...

  8. node服务端渲染(完整demo)

    简介 nodejs搭建多页面服务端渲染 技术点 koa 搭建服务 koa-router 创建页面路由 nunjucks 模板引擎组合html webpack打包多页面 node端异步请求 服务端日志打 ...

  9. React 服务端渲染方案完美的解决方案

    最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法.在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢? 什么是服务 ...

随机推荐

  1. 用Meta 取消流量器缓存方便调试

    <!-- 禁止浏览器从本地缓存中调阅页面.--> <meta http-equiv="pragram" content="no-cache"& ...

  2. antd 如何让 Row 中的 Col 自动换行?

    1.解决方案 在需要换行处,设置一个空的 Col // 空白(特殊情况处理) const empty = ( <Col md={6} sm={24}></Col> ); .

  3. MySQL中insert ignore into, on duplicate key update,replace into,insert … select … where not exist的一些用法总结

    在MySQL中进行条件插入数据时,可能会用到以下语句,现小结一下.我们先建一个简单的表来作为测试: CREATE TABLE `books` ( `id` ) NOT NULL AUTO_INCREM ...

  4. JS基础——构造函数VS原型

    JS是一种基于对象的语言.在使用过程中不免遇到复制对象的问题.但通常我们採用的直接赋值'obj1=obj2'这样的做法会出现数据覆盖问题. 也就是对象引用过程中引用地址一致.导致对象数据被改动的问题. ...

  5. sql select(A.B)拼接

    需要做的工作:把DBtable里边的某两个字段,(当然可以更多)或者不同表,道理类似,用某个符号拼接起来. 比如(Table.A).(Tables.B) oracle里边可以这样写,sql没试: se ...

  6. android 项目R文件丢失解决的方法

    R文件丢失的原因有非常多,这里提供几种解决的方法: 1.  选中项目,点击 Project - Clean , 清理一下项目. 2. 选中项目,右键 选择 Android Tools  - Fix P ...

  7. 利用ctypes调用Fortran程序

    本来python下面调用fortran最傻瓜方便的办法就是f2py,但是若fortran和C混合编程的代码,分别指定gfortran和gcc为编译器,在windows下面f2py直接报错 那么ctyp ...

  8. scala进阶笔记:函数组合器(combinator)

    collection基础参见之前的博文scala快速学习(二). 本文主要是组合器(combinator),因为在实际中发现很有用.主要参考:http://www.importnew.com/3673 ...

  9. 更多的使用自定义元素(CustomElement)。

    更多的使用自定义元素(CustomElement).

  10. div 下 的img水平居中

    设置text-align:center; 这个div必须要设置宽度: 如:{text-align:center; width:100%;}