Java后端+PhantomJS +Echars生成数据图表

    这次遇到的问题要在发送email时,生成好看的数据图表,所以初步思路就是:java服务端+echars。由于echars是需要用js执行的,所以还需要加入执行环境PhantomJS 。

    PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API。原生支持各种Web标准:DOM处理,CSS选择器,JSON,Canvas,和SVG。PhantomJS可以用于页面自动化,网络监测,网页截屏,以及无界面测试等。

    第一种方式是前端+echars,生成图表后,后台使用phantomjs进行进行截屏,这个方式我试了可行,但是增加了前端的工作量,丢掉。

    下面这种方式,是利用PhantomJS 是一个js执行环境,通过拼凑出cmd的执行命令,把绘图所需要的数据,组装成echars需要的格式一并传入。即通过后台(Java)执行PhantomJS,调用echarts-convert.js+数据,并输出成图片。

①开发环境准备:

    去git上下载echartsconvert,本次phantomjs.exe执行的就是echarts-convert.js,它引用了echarts.min.js和jquery-3.2.1.min.js。

    下载phantomjs-2.1.1-windows。linux和mac有对应的版本,使用的时候配置phantomjs-2.1.1-windows\bin\phantomjs.exe的路径到cmd命令里就行。


②Demo:

public class EcharsServiceImpl implements EcharsService {

        private static final String JSpath = "D:/AAAA/A/echartsconvert/script/echarts-convert.js";    //echarts.js的存放路径

        private static final String phantomjs = "D:/AAAA/A/phantomjs-2.1.1-windows/bin/phantomjs.exe";    //PhantomJS的存放路径

        public static void main(String[] args) {

                String optiona =Constant.dd;     //应用预先定义的测试数据,Constant.aa,bb,cc,dd,ee在后面给你们

                generateEChart(optiona);

           }


    public static String generateEChart(String options) {

        String dataPath = writeFile(options);     //把参数放文件里落地

        String path = "D:/AAAA/A/Echart/"+UUID.randomUUID()+".png";

        try {

            File file = new File(path);

            if (!file.exists()) { 

                File dir = new File(file.getParent());

                dir.mkdirs();

                file.createNewFile();

            }

            String blank = " ";

            String cmd = phantomjs +blank+ JSpath + " -infile " + dataPath + " -outfile " + file;

            Process process = Runtime.getRuntime().exec(cmd);

            InputStream inputStream = process.getInputStream();

            //System.out.println(inputStream.read());       看一下流,输出-1就得检查一下前头的cmd了

            BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));

            //String line = "";

            //while ((line = input.readLine()) != null) {

            //System.out.println(line);

            //}

            input.close();

        } catch (IOException e) {

            e.printStackTrace();

        }finally{

            return path;

        }

    }


    /**

    * 把数据写入文件,调试demo的时候,可以跳过这段,直接指定xxx.json

    */

    public static String writeFile(String options) {

        String dataPath="D:/AAAA/A/Echart/"+ UUID.randomUUID().toString().substring(0, 8) +".json";

        try {

            /* 写入Json文件 */

            File writename = new File(dataPath); // 相对路径,如果没有则要建立一个新的output.txt文件

            if (!writename.exists()) {  //文件不存在则创建文件,先创建目录

                File dir = new File(writename.getParent());

                dir.mkdirs();

                writename.createNewFile(); // 创建新文件

            }

            BufferedWriter out = new BufferedWriter(new FileWriter(writename));

            out.write(options);

            out.flush(); // 把缓存区内容压入文件

            out.close(); // 最后记得关闭文件

        } catch (IOException e) {

            e.printStackTrace();

        }

        return dataPath;

    }

}

③测试数据准备

    测试数据要自己到echars的官网上找(https://echarts.baidu.com/examples/#chart-type-tree),每种图表的option不一样,单击下面不同类型的图进去,组装合适的option。组装的时候要记得修改key-value中value的单引号。

    我在下面的常量里准备了饼图、折线图、漏斗图、仪表盘四种简单数据。

/**

* 供echars模拟的数据

* @author PENGJING973

*/

public class Constant {

/**饼图*/

public static final String aa = "{tooltip:{trigger:'item',formatter:'{a} <br/>{b}: {c} ({d}%)'},legend:{orient:'vertical',x:'left',data:['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']},series:[{name:'访问来源',type:'pie',radius:['50%','70%'],avoidLabelOverlap:false,label:{normal:{show:false,position:'center'},emphasis:{show:true,textStyle:{fontSize:'30',fontWeight:'bold'}}},labelLine:{normal:{show:false}},data:[{value:335,name:'直接访问'},{value:310,name:'邮件营销'},{value:234,name:'联盟广告'},{value:135,name:'视频广告'},{value:1548,name:'搜索引擎'}]}]}";

/**折线图 */

public static final String bb = "{\"title\":{\"text\":\"电流图\",\"subtext\":\"电流图\",\"x\":\"left\"},\"toolbox\":{\"feature\":{\"saveAsImage\":{\"show\":true,\"title\":\"保存为图片\",\"type\":\"png\",\"lang\":[\"点击保存\"]}},\"show\":true},\"tooltip\":{\"trigger\":\"axis\"},\"legend\":{\"data\":[\"邮件营销\",\"联盟广告\",\"视频广告\"]},\"xAxis\":[{\"type\":\"category\",\"boundaryGap\":false,\"data\":[\"周一\",\"周二\",\"周三\",\"周四\",\"周五\",\"周六\",\"周日\"]}],\"yAxis\":[{\"type\":\"value\"}],\"series\":[{\"name\":\"邮件营销\",\"type\":\"line\",\"stack\":\"总量\",\"data\":[120,132,101,134,90,230,210]},{\"name\":\"联盟广告\",\"type\":\"line\",\"stack\":\"总量\",\"data\":[220,182,191,234,290,330,310]},{\"name\":\"视频广告\",\"type\":\"line\",\"stack\":\"总量\",\"data\":[150,232,201,154,190,330,410]}]}";

/**漏斗图*/

public static final String cc = "{title:{text:'漏斗图(对比)',subtext:'纯属虚构',left:'left',top:'bottom'},tooltip:{trigger:'item',formatter:'{a} <br/>{b} : {c}%'},toolbox:{show:true,orient:'vertical',top:'center',feature:{dataView:{readOnly:false},restore:{},saveAsImage:{}}},legend:{orient:'vertical',left:'left',data:['产品A','产品B','产品C','产品D','产品E']},calculable:true,series:[{name:'漏斗图',type:'funnel',width:'40%',height:'45%',left:'5%',top:'50%',funnelAlign:'right',center:['25%','25%'],data:[{value:60,name:'产品C'},{value:30,name:'产品D'},{value:10,name:'产品E'},{value:80,name:'产品B'},{value:100,name:'产品A'}]},{name:'金字塔',type:'funnel',width:'40%',height:'45%',left:'5%',top:'5%',sort:'ascending',funnelAlign:'right',center:['25%','75%'],data:[{value:60,name:'产品C'},{value:30,name:'产品D'},{value:10,name:'产品E'},{value:80,name:'产品B'},{value:100,name:'产品A'}]},{name:'漏斗图',type:'funnel',width:'40%',height:'45%',left:'55%',top:'5%',funnelAlign:'left',center:['75%','25%'],data:[{value:60,name:'产品C'},{value:30,name:'产品D'},{value:10,name:'产品E'},{value:80,name:'产品B'},{value:100,name:'产品A'}]},{name:'金字塔',type:'funnel',width:'40%',height:'45%',left:'55%',top:'50%',sort:'ascending',funnelAlign:'left',center:['75%','75%'],data:[{value:60,name:'产品C'},{value:30,name:'产品D'},{value:10,name:'产品E'},{value:80,name:'产品B'},{value:100,name:'产品A'}]}]}";

/**仪表盘*/

public static final String dd ="{tooltip:{formatter:'{a} <br/>{c} {b}'},toolbox:{show:true,feature:{restore:{show:true},saveAsImage:{show:true}}},series:[{name:'速度',type:'gauge',z:3,min:0,max:220,splitNumber:11,radius:'50%',axisLine:{lineStyle:{width:10}},axisTick:{length:15,lineStyle:{color:'auto'}},splitLine:{length:20,lineStyle:{color:'auto'}},axisLabel:{backgroundColor:'auto',borderRadius:2,color:'#eee',padding:3,textShadowBlur:2,textShadowOffsetX:1,textShadowOffsetY:1,textShadowColor:'#222'},title:{fontWeight:'bolder',fontSize:20,fontStyle:'italic'},detail:{formatter:function(value){value=(value+'').split('.');value.length<2&&(value.push('00'));return('00'+value[0]).slice(-2)+'.'+(value[1]+'00').slice(0,2);},fontWeight:'bolder',borderRadius:3,backgroundColor:'#444',borderColor:'#aaa',shadowBlur:5,shadowColor:'#333',shadowOffsetX:0,shadowOffsetY:3,borderWidth:2,textBorderColor:'#000',textBorderWidth:2,textShadowBlur:2,textShadowColor:'#fff',textShadowOffsetX:0,textShadowOffsetY:0,fontFamily:'Arial',width:100,color:'#eee',rich:{}},data:[{value:40,name:'km/h'}]},{name:'转速',type:'gauge',center:['20%','55%'],radius:'35%',min:0,max:7,endAngle:45,splitNumber:7,axisLine:{lineStyle:{width:8}},axisTick:{length:12,lineStyle:{color:'auto'}},splitLine:{length:20,lineStyle:{color:'auto'}},pointer:{width:5},title:{offsetCenter:[0,'-30%'],},detail:{fontWeight:'bolder'},data:[{value:1.5,name:'x1000 r/min'}]},{name:'油表',type:'gauge',center:['77%','50%'],radius:'25%',min:0,max:2,startAngle:135,endAngle:45,splitNumber:2,axisLine:{lineStyle:{width:8}},axisTick:{splitNumber:5,length:10,lineStyle:{color:'auto'}},axisLabel:{formatter:function(v){switch(v+''){case'0':return'E';case'1':return'Gas';case'2':return'F';}}},splitLine:{length:15,lineStyle:{color:'auto'}},pointer:{width:2},title:{show:false},detail:{show:false},data:[{value:0.5,name:'gas'}]},{name:'水表',type:'gauge',center:['77%','50%'],radius:'25%',min:0,max:2,startAngle:315,endAngle:225,splitNumber:2,axisLine:{lineStyle:{width:8}},axisTick:{show:false},axisLabel:{formatter:function(v){switch(v+''){case'0':return'H';case'1':return'Water';case'2':return'C';}}},splitLine:{length:15,lineStyle:{color:'auto'}},pointer:{width:2},title:{show:false},detail:{show:false},data:[{value:0.5,name:'gas'}]}]}";

}

④生成效果

        分别修改第二步main方法中optiona 的值,等于Constant.aa,bb,cc,dd,ee,观察到D:\AAAA\A\Echart\文件夹下生成的json文件和png文件。

    echars的js参考了这位前辈的csdn:https://blog.csdn.net/leftwukaixing/article/details/89449071,感谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容