得益于echarts和其他多种数据可视化框架的流行,现在做出各种美观大气炫酷的图形化报表已经是信手拈来的事情,接踵而来的就是各种新鲜的奇葩需求。最近我们就遇到一个,要能够将多张热力图合成为一张动图,展现出过去一段时间的变化趋势,然后再通过qq/微信分享出去。用户爸爸的脑洞开得不错,仔细一想也有道理,毕竟不是每个人都装了我们的app啊。
解决的思路也中规中矩,第一步,echart页面先发起数据请求,得到应该生成图片的起始时间和数量;第二步,由echart页面的js画出图表,通过js上传到服务端(java),循环这个过程,直到所有图片上传成功;第三步,在服务端将多张图片合成为gif,保存起来。这一步偷懒没有自己写,github上面找了一个很轻量的库(https://github.com/rtyley/animated-gif-lib-for-java),实测效果还不错。
整体来讲很简单,但是这里面有个坑就是第一步echarts页面发起请求,需要用户访问这个页面才行。由于里面有大量的js执行,curl显然是不行的。必须要通过浏览器访问。Windows用户可以很愉快的写个计划任务调用chrome每天运行一次就搞定了,没有图形化界面的linux用户就要hard一点点了。一开始尝试的是网上普遍流行的方法:selenium+chrome headless+chromedriver。这种方法的起源其实是自动化测试,但是我们的需求是一个浏览器,把页面上所有js给我跑一遍。最后这个方式是失败了,原因是chromedriver的局限——它可以渲染整个页面,也可以调用某个js方法(By JavaScriptExecutor.executeScript()),但是它不能把页面上的js和导入的js全部跑一遍,就像一个普通的浏览器那样。成功的方法其实更简单,就是让chrome运载在虚拟的X Window-Xvfb。注意Xvfb安装之后需要安装中文字库和图表需要用到的字体(从windows复制过来即可)。
Xvfb -ac :1 -screen 0 1280x1024x16
export DISPLAY=:1
google-chrome-stable --disable-gpu http://xxx.html