一、场景需求
前端不用等待获取数据渲染echarts图表,直接请求后台,获取echarts图表的base64编码,生成本地图片。
二、使用工具
1.下载:Phantomjs:https://phantomjs.org/download.html
添加的环境变量为:;D:\phantomjs\bin
phantomjs --version 测试版本提示版本说明安装成功
2.echart-convert.js
3. echarts.min.js
4.jquery-3.6.0.min.js ( https://code.jquery.com/jquery-3.6.0.min.js )
2-4代码下载( https://www.aliyundrive.com/s/3EuVNiiFiUQ )
生成图片命令:
phantomjs F:\ws\export02\tools\echarts-convert.js -infile F:\ws\export02\tools\option.js -width 800 -height 800
三、实现思路
前端发送请求,后台根据请求获取渲染echarts所需的数据option,通过phantomjs进行无界面浏览器的echarts渲染,渲染成功后获取echarts对象的base64编码。
四、代码
1.项目结构
echarts.min.js,echarts-convert.js,jquery-3.6.0.min.js 这个三个文件需要放在同一个文件夹中。示例如下图:
package com.zyn.util; import java.io.BufferedReader; import java.io.InputStreamReader; import com.sun.jndi.toolkit.url.Uri; import org.junit.Test; import sun.misc.BASE64Decoder; import java.io.*; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * @Title: EchartsTest * @Date 2022/5/11 17:28 * @Author Yinan * @Description: 测试Echarts后台渲染生成图片 */ public class EchartsTest { /** * phantomjs 路径 */ private static String PHANTOMJS_PATH = "E:\\Develop\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe"; /** * echartsJs 路径 */ private static String ECHARTS_PATH = "F:\\ws\\export02\\tools\\echarts-convert.js"; /** * echarts渲染所需数据 路径 */ private static String OPTION_PATH = "F:\\ws\\export02\\tools\\option.js"; private static String OUT_PATH = "F:\\ws\\export02\\tools\\img.png"; /** * echarts获取图片base64编码URL头 */ private static final String BASE64FORMAT = "data:image/png;base64,"; @Test public void echartsTest() throws Exception { BufferedReader input = null; String line; String base64 = ""; try { /** * 命令格式: * phantomjs echarts-convert.js -infile optionURl -width width -height height * 可选参数:-width width -height height * 备注: * phantomjs添加到环境变量中后可以直接使用,这里防止环境变量配置问题所以直接使用绝对路径 */ String cmd = " phantomjs " + ECHARTS_PATH + " -infile " + OPTION_PATH + " -width " + 800 + " -height " + 800; Process process = Runtime.getRuntime().exec(cmd); /** * 获取控制台输出信息 * 通过JS中使用console.log()打印输出base64编码 * 获取进程输入流,进行base64编码获取 */ input = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((line = input.readLine()) != null) { if (line.startsWith(BASE64FORMAT)) { base64 = line;//.replace(BASE64FORMAT, ""); break; } } } catch (Exception e) { e.printStackTrace(); } finally { try { input.close(); } catch (Exception e) { e.printStackTrace(); } } System.out.println(base64); getFileFromBase64(base64); } public File getFileFromBase64(String base) throws Exception { String base64Pic = base; File file = null; Map<String, Object> resultMap = new HashMap<String, Object>(); if (base64Pic == null) { // 图像数据为空 resultMap.put("resultCode", 0); resultMap.put("msg", "图片为空"); } else { BASE64Decoder decoder = new BASE64Decoder(); String baseValue = base64Pic.replaceAll(" ", "+");//前台在用Ajax传base64值的时候会把base64中的+换成空格,所以需要替换回来。 byte[] b = decoder.decodeBuffer(baseValue.replace("data:image/png;base64,", ""));//去除base64中无用的部分 base64Pic = base64Pic.replace("base64,", ""); SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd"); String nowDate = df2.format(new Date()); String imgFilePath = "f:\\" + nowDate + "\\" + System.currentTimeMillis(); File file1 = new File(imgFilePath); if (!file1.exists() && !file1.isDirectory()) {//判断文件路径下的文件夹是否存在,不存在则创建 file1.mkdirs(); } try { for (int i = 0; i < b.length; ++i) { if (b[i] < 0) {// 调整异常数据 b[i] += 256; } } file = new File(imgFilePath + "\\" + System.currentTimeMillis()+".png"); // 如果要返回file文件这边return就可以了,存到临时文件中 OutputStream out = new FileOutputStream(file.getPath()); out.write(b); out.flush(); out.close(); } catch (Exception e) { resultMap.put("resultCode", 0); resultMap.put("msg", "存储异常"); } } return file; } }
3.JS脚本 echarts-convert.js 代码如下(示例): (function () { var system = require('system'); var fs = require('fs'); var config = { // define the location of js files JQUERY: 'jquery-3.6.0.min.js', ECHARTS: 'echarts.min.js', // default container width and height DEFAULT_WIDTH: '600', DEFAULT_HEIGHT: '700' }, parseParams, render, pick, usage; // 提示:命令格式 usage = function () { console.log("\n" + "Usage: phantomjs echarts-convert.js -infile URL -width width -height height" + "\n"); }; // 选择是否存在设置长宽,否使用默认长宽 pick = function () { var args = arguments, i, arg, length = args.length; for (i = 0; i < length; i += 1) { arg = args[i]; if (arg !== undefined && arg !== null && arg !== 'null' && arg != '0') { return arg; } } }; // 处理参数 parseParams = function () { var map = {}, i, key; if (system.args.length < 2) { usage(); phantom.exit(); } for (i = 0; i < system.args.length; i += 1) { if (system.args[i].charAt(0) === '-') { key = system.args[i].substr(1, i.length); if (key === 'infile') { // get string from file // force translate the key from infile to options. key = 'options'; try { map[key] = fs.read(system.args[i + 1]).replace(/^\s+/, ''); } catch (e) { console.log('Error: cannot find file, ' + system.args[i + 1]); phantom.exit(); } } else { map[key] = system.args[i + 1].replace(/^\s+/, ''); } } } return map; }; render = function (params) { var page = require('webpage').create(), createChart; page.onConsoleMessage = function (msg) { console.log(msg); }; page.onAlert = function (msg) { console.log(msg); }; createChart = function (inputOption, width, height) { var counter = 0; function decrementImgCounter() { counter -= 1; if (counter < 1) { console.log("The images load error"); } } function loadScript(varStr, codeStr) { var script = $('<script>').attr('type', 'text/javascript'); script.html('var ' + varStr + ' = ' + codeStr); document.getElementsByTagName("head")[0].appendChild(script[0]); if (window[varStr] !== undefined) { console.log('Echarts.' + varStr + ' has been parsed'); } } function loadImages() { var images = $('image'), i, img; if (images.length > 0) { counter = images.length; for (i = 0; i < images.length; i += 1) { img = new Image(); img.onload = img.onerror = decrementImgCounter; img.src = images[i].getAttribute('href'); } } else { console.log('The images have been loaded'); } } // load opitons if (inputOption != 'undefined') { // parse the options loadScript('options', inputOption); // disable the animation options.animation = false; } // we render the image, so we need set background to white. $(document.body).css('backgroundColor', 'white'); var container = $("<div>").appendTo(document.body); container.attr('id', 'container'); container.css({ width: width, height: height }); // render the chart var myChart = echarts.init(container[0]); myChart.setOption(options); // load images loadImages(); return myChart.getDataURL(); }; // parse the params page.open("about:blank", function (status) { // inject the dependency js page.injectJs(config.JQUERY); page.injectJs(config.ECHARTS); var width = pick(params.width, config.DEFAULT_WIDTH); var height = pick(params.height, config.DEFAULT_HEIGHT); // create the chart var base64 = page.evaluate(createChart, params.options, width, height); console.log(base64); // define the clip-rectangle console.log('\nbase64 complete'); // exit phantom.exit(); }); }; // get the args var params = parseParams(); // validate the params if (params.options === undefined || params.options.length === 0) { console.log("ERROR: No options or infile found."); usage(); phantom.exit(); } // render the image render(params); }());
4.测试数据代码 option.js
option = { title: { text: 'ECharts 入门示例' }, tooltip: {}, legend: { data: ['销量'] }, xAxis: { data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] }, yAxis: {}, series: [ { name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] } ] }
标签:java,width,base64,Echarts,height,var,后台,js,echarts From: https://www.cnblogs.com/zzsuje/p/16733796.html