Java后台生成ECharts图片

前言

 通过echarts的jar包,Java后台生成一张图片,并把图片插入到word中。关于word插图片的代码在下一章。

 需要用到的工具PhantomJS,Echarts-convert.js,jquery.js,echarts.js

1.PhantomJS 介绍

PhantomJS是一个不需要浏览器的富客户端。 

官方介绍:PhantomJS是一个基于 WebKit 的服务器端JavaScript API。它全面支持web而不需浏览器支持,支持各种Web标准:DOM处理,CSS选择器, JSON,Canvas,和SVG。
PhantomJS常用于页面自动化,网络监测,网页截屏,以及无界面测试等。

通常我们使用PhantomJS作为爬虫工具。传统的爬虫只能单纯地爬取html的代码,对于js渲染的页面,就无法爬取,如Echarts统计图。而PhantomJS正可以解决此类问题。

 我们可以这么理解PhantomJS,PhantomJS是一个无界面、可运行脚本的谷歌浏览器。

1.1 PhantomJS下载安装

PhantomJS安装非常简单,官网http://phantomjs.org/download.html下载最新的安装包, 安装包有Windows,Mac OS X, Linux 64/32 bit,选择对应的版本下载解压即可使用,在下载包里有个example文件夹,里面对应了许多示例供参考。

为方便使用,我们将phantomjs添加至环境变量中。

windows下操作:

path 下添加  C:\Users\ming\Desktop\java-echarts\phantomjs-2.1.1-windows\bin
打开cmd,查看是否配置成功
C:\Users\ming>phantomjs --version
2.1.1

linux 下操作:

export PHANTOMJS=/usr/local/phantomjs/phantomjs-2.1.1-linux-x86_64
export PATH=$PATH:$PHANTOMJS/bin
# or
export PATH=$PATH:/usr/local/phantomjs/phantomjs-2.1.1-linux-x86_64/bin
# 刷新配置
source /etc/profile

注:linux虽然不需要其他的依赖包,但仍旧需要GLIBCXX_3.4.9和GLIBC_2.7,当然大多数linux是有这两个依赖包的。

 1.2 运行脚本测试

 安装包下 example 文件夹下提供了好多示例,这里以hello.js 为例,在example文件夹下输入 phantomjs hello.js 命令 会输出 Hello, world! 更多用法可参考官方文档。

C:\Users\ming\Desktop\java-echarts\phantomjs-2.1.1-windows\examples>phantomjs hello.js
Hello, world!

 2.Echartsconvert

上面讲述了PhantomJS如何使用,下面我们就从Echarts官网使用JS截图的方式来获取我们想要的图片 

Echartsconvert (Gitee)copy下来代码
注意:因为该源码长期没有更新,script目录下echarts.min.js太过于老旧,无法支持目前Echarts的图形,请大家copy下代码后,更新替换其文件 。最新echarts.min.js下载传送门 

其中echarts-convert.js就是我们要使用到的主C,这个Js就相当于帮我们去Echarts官方运行Dome->生成折线图/柱状图->保存到指定文件夹下

jquery.js自行下载对应版本,我的是3.6.3

附上echarts-converts.js文件


;(function (window, document, undefined) {
    "use strict";

    // 引入module
    var system = require('system'), // 获取参数
        path = phantom.libraryPath,
        command = require(path + '/module/command.js');// 参数module

    /**
     * phantomJs 全局异常监听
     * @param msg
     * @param trace
     */
    phantom.onError = function (msg, trace) {
        var msgStack = ['Convert 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('\n'));
        phantom.exit(1);
    };

    /**
     * 参数
     * @type {Command}
     */
    var commandParams = command
        .version('0.0.1')
        .option('-s, --server', 'provide echarts convert http server')
        .option('-p, --port ', 'change server port when add -s or --server', 9090)
        .option('-o, --opt ', 'add the param of echarts method [ eChart.setOption(opt) ]')
        .option('-t, --type ', 'provide file/base64 for image, default file', /^(file|base64)$/i, 'base64')
        .option('-f, --outfile ', 'add output of the image file path')
        .option('-w, --width ', 'change image width', '600')
        .option('-h, --height ', 'change image height', '400')
        .parse(system.args);


    // ***********************************
    // Echarts转换器
    // ***********************************
    function Convert(params) {
        this.params = params || commandParams; // 参数命令
        this.external = {
            JQUERY3: path + '/script/jquery-3.6.3.min.js',
            ECHARTS: path + '/script/echarts.min.js',
            ECHARTS_CHINA: path + '/script/china.js'
        }; // 外部js
    }

    /**
     * 初始化
     */
    Convert.prototype.init = function () {
        var params = this.params;
        this.check(params);
        if (params.server) {
            this.server(params);
        } else {
            this.client(params);
        }
    };

    /**
     * 参数检查
     * @param params
     */
    Convert.prototype.check = function (params) {
        if (undefined === params.server && undefined === params.opt) {
            this.error("option argument missing -o, --opt ");
        }

        if (undefined !== params.opt) {
            var isJson = this.checkJson(params.opt);
            if (!isJson) {
                this.error("--opt  args not json string");
            }
        }

        if ('file' === params.type && undefined === params.outfile) {
            this.createTmpDir();
        }

    };

    /**
     * 检查是否是json字符串
     * @param value
     * @returns {boolean}
     */
    Convert.prototype.checkJson = function (value) {
        var re = /^\{[\s\S]*\}$|^\[[\s\S]*\]$/;
        // 类型为string
        if (typeof value !== 'string') {
            return false;
        }
        // 正则验证
        if (!re.test(value)) {
            return false;
        }
        // 是否能解析
        try {
            value = "\"" + value + "\"";
            JSON.parse(value);
        } catch (err) {
            return false;
        }
        return true;
    };

    /**
     * 创建临时目录,并指定输出路径
     */
    Convert.prototype.createTmpDir = function () {
        var fs = require('fs'); // 文件操作
        var tmpDir = fs.workingDirectory + '/tmp';
        // 临时目录是否存在且可写
        if (!fs.exists(tmpDir)) {
            if (!fs.makeDirectory(tmpDir)) {
                this.error('Cannot make ' + tmpDir + ' directory\n');
            }
        }
        this.params.outfile = tmpDir + "/" + new Date().getTime() + ".png";
    };

    /**
     * 服务
     * @param params
     */
    Convert.prototype.server = function (params) {
        var server = require('webserver').create(), // 服务端
            convert = this;

        var listen = server.listen(params.port, function (request, response) {
            /**
             * 输出
             * @param data
             * @param success
             */
            function write(data, success, msg) {
                response.statusCode = 200;
                response.headers = {
                    'Cache': 'no-cache',
                    'Content-Type': 'application/json;charset=utf-8'
                };
                response.write(convert.serverResult(data, success, msg));
                response.close();
            }

            //获取参数
            var args = convert.serverGetArgs(request);

            if (args.opt !== undefined) {
                var check = convert.serverCheckAndSet(params, args);

                if (check) {
                    convert.client(params, write);
                } else {
                    write("", false, "failed to get image, please check parameter [opt] is a JSON");
                }
            } else {
                write("", false, "failed to get image, missing parameter [opt]");
            }

        });

        // 判断服务是否启动成功
        if (!listen) {
            this.error("could not create echarts-convert server listening on port " + params.port);
        } else {
            console.log("echarts-convert server start success. [pid]=" + system.pid);
        }
    };

    /**
     * 服务参数检查和赋值
     * @param params
     * @param args
     * @returns {boolean}
     */
    Convert.prototype.serverCheckAndSet = function (params, args) {
        if (this.checkJson(args.opt)) {
            params.opt = args.opt;
        } else {
            return false;
        }

        if (/^(file|base64)$/i.exec(args.type)) {
            params.type = args.type;
        }

        if (!isNaN(args.width)) {
            params.width = args.width;
        }

        if (!isNaN(args.height)) {
            params.height = args.height;
        }
        return true;
    };

    /**
     * 结果返回
     * @param data
     * @param success
     * @param msg
     */
    Convert.prototype.serverResult = function (data, success, msg) {
        var result = {
            code: success ? 1 : 0,
            msg: undefined === msg ? success ? "success" : "failure" : msg,
            data: data
        };

        return JSON.stringify(result);
    };

    /**
     * 获取参数
     * @param request
     * @returns {{}}
     */
    Convert.prototype.serverGetArgs = function (request) {
        var args = {};
        if ('GET' === request.method) {
            var index = request.url.indexOf('?');
            if (index !== -1) {
                var getQuery = request.url.substr(index + 1);
                args = this.serverParseArgs(getQuery);
            }
        } else if ('POST' === request.method) {
            var postQuery = request.post;
            args = this.serverParseArgs(postQuery);
        }
        return args;
    };

    /**
     * 解析参数
     * @param query 字符串
     * @returns {{}} 对象
     */
    Convert.prototype.serverParseArgs = function (query) {
        var args = {},
            pairs = query.split("&");
        for (var i = 0; i < pairs.length; i++) {
            var pos = pairs[i].indexOf('=');
            if (pos === -1)
                continue;
            var key = pairs[i].substring(0, pos);
            var value = pairs[i].substring(pos + 1);
            // 中文解码,必须写两层
            value = decodeURIComponent(decodeURIComponent(value));
            args[key] = value;
        }
        return args;
    };

    /**
     * 访问渲染
     * @param params
     * @param fn
     */
    Convert.prototype.client = function (params, fn) {
        var page = require('webpage').create(); // 客户端
        var convert = this,
            external = this.external,
            render,
            output;

        /**
         *  渲染
         * @returns {*}
         */
        render = function () {
            switch (params.type) {
                case 'file':
                    // 渲染图片
                    page.render(params.outfile);
                    return params.outfile;
                case 'base64':
                default:
                    var base64 = page.renderBase64('PNG');
                    return base64;

            }
        };

        /**
         * 输出
         * @param content 内容
         * @param success 是否成功
         */
        output = function (content, success, msg) {
            if (params.server) {
                fn(content, success, msg);
                page.close();
            } else {
                console.log(success ? "[SUCCESS]:" : "[ERROR]:" + content);
                page.close();
                convert.exit(params);// exit
            }
        };

        /**
         * 页面console监听
         * @param msg
         * @param lineNum
         * @param sourceId
         */
        page.onConsoleMessage = function (msg, lineNum, sourceId) {
            console.log(msg);
        };

        /**
         * 页面错误监听
         * @param msg
         * @param trace
         */
        page.onError = function (msg, trace) {
            output("", false, msg); // 失败,返回错误信息
        };

        // 空白页
        page.open("about:blank", function (status) {
            // 注入依赖js包
            var hasJquery = page.injectJs(external.JQUERY3);
            var hasEchart = page.injectJs(external.ECHARTS);
            var hasEchartChina = page.injectJs(external.ECHARTS_CHINA);

            // 检查js是否引用成功
            if (!hasJquery && !hasEchart) {
                output("Could not found " + external.JQUERY3 + " or " + external.ECHARTS, false);
            }

            // 创建echarts
            page.evaluate(createEchartsDom, params);

            // 定义剪切范围,如果定义则截取全屏
            page.clipRect = {
                top: 0,
                left: 0,
                width: params.width,
                height: params.height
            };

            // 渲染
            var result = render();
            // 成功输出,返回图片或其他信息
            output(result, true);
        });
    };

    /**
     * 创建eCharts Dom层
     * @param params 参数
     */
    function createEchartsDom(params) {
        // 动态加载js,获取options数据
        $('
                    
                    

你可能感兴趣的:(Java学习笔记,echarts,javascript,后端生成echarts图片,echarts-convert,phantomjs)