实现node端渲染图表的简单方案
实现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参数,传递给浏览器,在浏览器端拿到对应的参数进行渲染,所以基本实现步骤如下:
传递参数到node层render函数中
接收到render中option参数传递给浏览器的window对象
浏览器运行时从window对象中获取options渲染对应的结果
执行截图操作,保存渲染结果
可以用如下伪代码表示:
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端渲染图表的简单方案的更多相关文章
- 服务端渲染和nuxt简单介绍
概述 最近研究了一下服务端渲染,有一些心得,记录下来供以后开发时参考,相信对其他人也有用. 参考资料: Vue SSR指南 nuxt.js官网 服务端渲染介绍 服务端渲染简单来说,就是分别对项目用we ...
- 实例PK(Vue服务端渲染 VS Vue浏览器端渲染)
Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...
- Vue服务端渲染和Vue浏览器端渲染的性能对比
Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十五║初探SSR服务端渲染(个人博客二)
缘起 时间真快,现在已经是这个系列教程的下半部 Vue 第 12 篇了,昨天我也简单思考了下,可能明天再来一篇,Vue 就基本告一段落了,因为什么呢,这里给大家说个题外话,当时写博文的时候,只是想给大 ...
- Vue服务端渲染 VS Vue浏览器端渲染)
Vue 2.0 开始支持服务端渲染的功能,所以本文章也是基于vue 2.0以上版本.网上对于服务端渲染的资料还是比较少,最经典的莫过于Vue作者尤雨溪大神的 vue-hacker-news.本人在公司 ...
- Headless Chrome:服务端渲染JS站点的一个方案【上篇】【翻译】
原文链接:https://developers.google.com/web/tools/puppeteer/articles/ssr 注:由于英文水平有限,没有逐字翻译,可以选择直接阅读原文 tip ...
- vue服务端渲染简单入门实例
想到要学习vue-ssr的同学,自不必多说,一定是熟悉了vue,并且多多少少做过几个项目.然后学习vue服务端渲染无非解决首屏渲染的白屏问题以及SEO友好. 话不多说,笔者也是研究多日才搞明白这个服务 ...
- node服务端渲染(完整demo)
简介 nodejs搭建多页面服务端渲染 技术点 koa 搭建服务 koa-router 创建页面路由 nunjucks 模板引擎组合html webpack打包多页面 node端异步请求 服务端日志打 ...
- React 服务端渲染方案完美的解决方案
最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法.在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢? 什么是服务 ...
随机推荐
- Android安全机制介绍
Android的安全机制包含下面几个方面: • 进程沙箱隔离机制. • 应用程序签名机制. • 权限声明机制. • 訪问控制机制. • 进程通信机制. ...
- 用 centrifugo 搭建 消息推送服务器 docker + rancher 搭建
关于消息推送服务器 目前有很多第三方的开放成熟的推送服务.鉴于项目需要 我们项目需要自己搭建 自己的推送服务. 我们的推送应用场景 聊天消息 项目内部消息提醒 移动设备接受消息 应用到的相关软件工具知 ...
- react 使用 moment 进行 日期格式化
在react中使用得先导入: import moment from 'moment'; 调用: npm install moment var moment = require('moment'); m ...
- ISC DHCP: Enterprise grade solution for configuration needs
https://www.isc.org/downloads/dhcp/ ISC DHCP: Enterprise grade solution for configuration needs All ...
- LINQ解决依据某个字段去重
想要List结果反复 的数据非常easy.仅仅要.Dinstinct()就好了 可是假设想要依据某个字段去除反复的数据,上面的方法就帮不上忙了.我们须要重写一个方法.直接上样例吧 [Serializa ...
- [转载]php中深拷贝浅拷贝
转自:http://cnn237111.blog.51cto.com/2359144/1283163 PHP中提供了一种对象复制的操作,clone.语法颇为简单: $a = clone $b; 1.浅 ...
- 【python】How to change the Jupyter start-up folder
Copy the Jupyter Notebook launcher from the menu to the desktop. Right click on the new launcher and ...
- peewee模块
Peewee Python中数据库与ORM主要做这几件事: 数据库方面由程序员设计表关系,主要是1v1,1vN,NvN: ORM做数据类型映射,将数据库表示的char/int等类型映射成Python对 ...
- block-循环引用
在ARC机制下,app的内存管理由操作系统进行管理,不须要程序猿手动的管理内存,方便了开发.虽然,自己主动释放内存非常方便.可是并不是绝对安全,绝对不会产生内存泄露. 大部分导致iOS对象无法按预期释 ...
- JAVA学习第十九课(java程序的异常处理 (二))
异常处理的捕捉形式: 这是能够对异常进行针对性处理的方式 六.try.catch的理解 详细格式: try { //须要被检測异常的代码 } catch(异常类 变量)//改变量用于接受发生异常的对象 ...