使用PhantomJS在服务器端渲染并生成Echarts图片
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用PhantomJS在服务器端渲染并生成Echarts图片相关的知识,希望对你有一定的参考价值。
1,使用的jar包
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.github.abel533</groupId>
<artifactId>ECharts</artifactId>
<version>3.0.0.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.github.abel533</groupId>
<artifactId>ECharts</artifactId>
<version>3.0.0.2</version>
</dependency>
,2,创建要用的js(echarts-convert.js)
function Base64() {
// private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9+/=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/
/g,"
");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}
///////////////////////////////////
system = require(‘system‘); // 获取参数
var jspath = system.args[0];
var base64JsonStr = system.args[1];
//将base64解密
var paramsJsonStr = new Base64().decode(base64JsonStr) ;
//转换为json对象
var jsonObj = JSON.parse(paramsJsonStr);
var option = jsonObj.opt ;
var width = jsonObj.width ;
var height = jsonObj.height ;
var outfile = jsonObj.outfile ;
var fileSuffix = jsonObj.type ;
function Convert(params){
this.params = params ;
this.external = {
JQUERY3 : ‘jquery-1.9.1.min.js‘,
ECHARTS3 : ‘echarts3.8.5.min.js‘
}; // 外部js
this.page = require(‘webpage‘).create(); // 客户端
this.page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.log(‘----console----‘+msg);
};
var instance = this ;
this.page.onError = function(msg, trace) {
var msgStack = [‘PHANTOM ERROR: ‘ + msg];
if (trace && trace.length) {
msgStack.push(‘TRACE:‘);
trace.forEach(function(t) {
msgStack.push(‘ -> ‘ + (t.file || t.sourceURL) + ‘: ‘ + t.line + (t.function ? ‘ (in function ‘ + t.function +‘)‘ : ‘‘));
});
}
console.error(msgStack.join(‘
‘));
instance.output("", false, msg); // 失败,返回错误信息
};
}
Convert.prototype.init = function(){
var instance = this ;
instance.page.open("about:blank", function(status) {
// 注入依赖js包
var hasJquery = instance.page.injectJs(instance.external.JQUERY3);
var hasEchart = instance.page.injectJs(instance.external.ECHARTS3);
// 检查js是否引用成功
if (!hasJquery || !hasEchart) {
output("Could not found " + external.JQUERY3 + " or " + external.ECHARTS3, false);
}
// 创建echarts
instance.page.evaluate(instance.createEchartsDom, instance.params);
// 定义剪切范围,如果定义则截取全屏
instance.page.clipRect = {
top : 0,
left : 0,
width : instance.params.width,
height : instance.params.height
};
// 渲染
var result = instance.render();
// 成功输出,返回图片或其他信息
instance.output(result, true);
});
}
Convert.prototype.render = function(){
var instance = this ;
switch (instance.params.type) {
case ‘file‘:
// 渲染图片
instance.page.render(instance.params.outfile);
return instance.params.outfile;
case ‘base64‘:
default:
var base64 = instance.page.renderBase64(‘PNG‘);
return base64;
}
}
Convert.prototype.output = function(content, success, msg) {
var instance = this ;
console.log(success ? "[SUCCESS]:" : "[ERROR]:" + content);
instance.page.close();
instance.exit(instance.params); // exit
};
Convert.prototype.exit = function (params) {
phantom.exit();
};
//
// 创建eCharts Dom层
// @param params 参数
// params.opt
// params.width
// params.height
// params.outfile
// params.type = ‘PNG‘
//
Convert.prototype.createEchartsDom = function(params) {
console.log("---createEchartsDom--"+params.width) ;
var instance = this ;
options = params.opt ;
// 动态加载js,获取options数据
$(‘<script>‘)
.attr(‘type‘, ‘text/javascript‘) // .html(‘var options = ‘ + params.opt)
.appendTo(document.head);
// 取消动画,否则生成图片过快,会出现无数据
if (options !== undefined) {
options.animation = false;
}
// body背景设置为白色
$(document.body).css(‘backgroundColor‘, ‘white‘);
// echarts容器
var container = $("<div>")
.attr(‘id‘, ‘container‘)
.css({
width : params.width,
height : params.height
}).appendTo(document.body);
var eChart = echarts.init(container[0]);
eChart.setOption(options);
}
//构建,入口
new Convert(jsonObj).init();
3,Java代码
public class ImageRenderParams {
//echart的Option
public Option opt;
//echart图片的宽度
public int width = 600;
//echart图片的高度
public int height = 400;
//echart图片保存地址
public String outfile = "d:/dsafdf.png";
//file 或者 PNG
public String type = "file";
}
/**
* 创建Echart图
*
* @param imagePath 图片保存地址,例如:d:/demo.png
* @throws Exception
*/
public ImageResult createEchartImage(Option option) throws Exception {
if (option == null) {
return new ImageResult();
}
String imgPath = getRandomImagePath(option);
ImageRenderParams params = new ImageRenderParams();
params.opt = option;
params.outfile = imgPath;
// 实例化
Gson gson = new Gson();
// 将map转成JSON
String paramsJsonStr = gson.toJson(params);
Base64 base64 = new Base64();
//转换为base64编码是为了防止执行指令的时候出问题
String base64Str = base64.encodeToString(paramsJsonStr.getBytes("UTF-8"));
//调用的JS文件路径
File jsFile = ResourceUtils.getFile("classpath:static/js/echarts-convert.js");
// 生成的图片名称
String jsFilePath = jsFile.getAbsolutePath();
String[] args = new String[3];
args[0] = jsFilePath;
args[1] = base64Str;
// 执行脚本
try {
CommandExecUtil.phantomjsExec(args);
} catch (Exception e) {
throw e;
}
return new ImageResult(imgPath);
}
public static class ImageResult {
private String imagePath;
private byte[] imageData;
public ImageResult(String imagePath) {
this.imagePath = imagePath;
}
public ImageResult() {
}
public String getImagePath() {
return imagePath;
}
public byte[] getImageData() throws Exception {
if (StringUtils.isBlank(imagePath)) {
return null;
}
if (imageData != null) {
return imageData;
}
File file = ResourceUtils.getFile(imagePath);
if (file == null) {
return null;
}
FileInputStream fi = new FileInputStream(file);
imageData = new byte[fi.available()];
fi.read(imageData);
fi.close();
return imageData;
}
}
以上是关于使用PhantomJS在服务器端渲染并生成Echarts图片的主要内容,如果未能解决你的问题,请参考以下文章
如何用python+selenium+phantomjs获得一个网页的动态生成的html代码
使用 PhantomJS 和 node.js 保存和渲染网页
如何使用 webdriver (Java) 在 phantomjs 上禁用字体抗锯齿?