【Android】WebView中使用EChart 展示本地数据

写在开始之前

之前在项目中使用过MPAndroidChart 显示过数据图表,现在需要使用HTML + Echart 来显示,写了一个Demo,DEMO中实现了线图,饼图,还有柱状图。

示例代码地址:点击跳转到github

使用到的开源项目

  • EChart 库 -js
    • 版本:2.2.7
  • EChart java 对象库 这是一个针对ECharts3.x(2.x)版本的Java类库,实现了所有ECharts中的Json结构对应的Java对象,并且可以很方便的创建Option。这个库引用了Gson,所以build.gradle 中也要加入GSON 的依赖。
    • 版本 2.2.7

JS 和 html 编写

为方便测试,html页面和js代码放置于项目的assets 目录中,Android代码访问路径为:file:///android_asset/jsWeb/echart.html

html 页面编写

  1. 在head中引入 js 脚本,主要代码如下:(点击查看全部代码:echart.html)
    <head>
         <!-- 导入script -->
         <script src="http://echarts.baidu.com/echarts2/doc/example/www/js/echarts.js"></script>
        <script src="./android.js"></script>
    </head>
  1. body中请求需要的EChart脚本,并添加对应控件,主要代码如下: ( 点击查看全部代码:echart.html) 。 我在其中添加了一个js中指定数据的EChart 表格用于测试
 <div id="main" style="height:400px"></div>
    <script type="text/javascript">
            // 路径配置
            require.config({
              paths: {
                echarts: 'http://echarts.baidu.com/echarts2/doc/example/www/js'
                //echarts: './www/js'
              }
            });
            // 使用
            require(
              [
                'echarts',
                'echarts/chart/line', // 使用柱状图就加载line模块,按需加载
                'echarts/chart/bar', // 使用柱状图就加载bar模块,按需加载
                'echarts/chart/pie', // 使用柱状图就加载pie模块,按需加载
              ],
              function (ec) {
                // 基于准备好的dom,初始化echarts图表
                var myChart = ec.init(document.getElementById('main'));
                //设置数据
                var option = {
                // .... 数据部分
            };
                // 为echarts对象加载数据
                myChart.setOption(option);
              }
            )
    </script>

    <hr/>
    <p>
    <b>从Android 代码中获取数据绘制图表</b><br/>
    <button onClick="loadALineChart()" style="height:40px">线状图</button>
    <button onClick="loadAChart(2)" style="height:40px">饼状图</button>
    <button onClick="loadAChart(1)" style="height:40px">柱状图</button>

    <p id="textcontent">没有内容</p>
    <div id="chart2" style="height:400px"/>
    </p>

JS 脚本

这里有一点要注意:Android WebView 提供的接口返回String 类型的json option 字符串,而JS 端接受到字符串后需要用JSON.parse 方法转化成js的Object 对象,只有转换成对象之后才可以传入到Echart的setOption 方法中显示出来。
主要代码如下,点击查看全部代码

        function toast(msg){
        Android.showToast(msg);
        }

        function loadALineChart(){
            // 必须加JOSN.parse 转换数据类型
            var option = JSON.parse(Android.getLineChartOptions());

            var chart2Doc = document.getElementById('chart2');
            var myChart2 = require('echarts').init(chart2Doc);

            myChart2.setOption(option);
            document.getElementById('textcontent').innerHTML=option;
            toast(option);
        }

        /**
        type :  1 - 饼状图
                2 - 柱状图
        */
        function loadAChart(type){
            // 必须用JSON.parse() 转换一下,才可以显示,否则数据类型会不对
            var option = JSON.parse(Android.getPieChartOptions(type));
            var chart2Doc = document.getElementById('chart2');
            var myChart2 = require('echarts').init(chart2Doc);

            myChart2.setOption(option);
            document.getElementById('textcontent').innerHTML=option;
        }

Android 代码编写

1. WebAppInterface 定义和实现

点击查看全部文件内容

   /**
 * 注入到JS里的对象接口
 */
class WebAppInterface {
    Context mContext;

    public WebAppInterface(Context c) {
        mContext = c;
    }

    /**
     * 获取
     *
     * @return
     */
    @JavascriptInterface
    public String getLineChartOptions() {
        GsonOption option = markLineChartOptions();
        LogUtils.d(option.toString());
        return option.toString();
    }

    @JavascriptInterface
    public void showToast(String msg) {
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }

    /**
     * PieChart 或者柱状图数据示例
     * @param type 1 - 饼状图数据; 2 - 柱状图数据
     * @return
     */
    @JavascriptInterface
    public String getPieChartOptions(int type) {

        mWebView.post(new Runnable() {
            @Override
            public void run() {
                showDialog();
            }
        });
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //地址:http://echarts.baidu.com/doc/example/pie7.html
        GsonOption option = new GsonOption();
        // 设置标题
        option.title(new Title().text("某站点用户访问来源").subtext("纯属虚构").x(X.center));
        if(type == 2) {
            option.tooltip().trigger(Trigger.item).formatter("{a} <br/>{b} : {c} ({d}%)");
        }else  if(type == 1){
            option.tooltip().trigger(Trigger.item).formatter("{a} <br/>{b} : {c}");
        }
        // 设置图例
        option.legend().data("直接访问", "邮件营销", "联盟广告", "视频广告", "搜索引擎").orient(Orient.vertical).x(X.left);

        // 是否可以拖动以计算
        option.calculable(true);

        if(type == 2){
            // 构造数据
            Pie  pie1 = new Pie("访问来源");
            pie1.type(SeriesType.pie).radius("45%").center("50%","60%");
            pie1.data(new Data("直接访问",335),
                    new Data("邮件营销",310),
                    new Data("联盟广告",234),
                    new Data("视频广告",135),
                    new Data("搜索引擎",1548)
            );
            option.series(pie1);
        }else  if(type ==1) {
            // 构建柱状数据
            option.xAxis(new CategoryAxis().name("访问来源").data("视频广告","搜索引擎","联盟广告","邮件营销","直接访问"));
            option.yAxis(new ValueAxis());

            Bar bar = new Bar("访问来源");
            bar.data(11,4,14,45,67,88);
            option.series(bar);
        }
        Log.d("TAG",option.toString());
        mWebView.post(new Runnable() {
            @Override
            public void run() {
                dismissDialog();
            }
        });
        return option.toString();
    }


    @JavascriptInterface
    public GsonOption markLineChartOptions() {
        GsonOption option = new GsonOption();
        option.legend("高度(km)与气温(°C)变化关系");

        option.toolbox().show(true).feature(Tool.mark, Tool.dataView, new MagicType(Magic.line, Magic.bar), Tool.restore, Tool.saveAsImage);

        option.calculable(true);
        option.tooltip().trigger(Trigger.axis).formatter("Temperature : <br/>{b}km : {c}°C");

        ValueAxis valueAxis = new ValueAxis();
        valueAxis.axisLabel().formatter("{value} °C");
        option.xAxis(valueAxis);

        CategoryAxis categoryAxis = new CategoryAxis();
        categoryAxis.axisLine().onZero(false);
        categoryAxis.axisLabel().formatter("{value} km");
        categoryAxis.boundaryGap(false);
        categoryAxis.data(0, 10, 20, 30, 40, 50, 60, 70, 80);
        option.yAxis(categoryAxis);

        Line line = new Line();
        line.smooth(true).name("高度(km)与气温(°C)变化关系").data(15, -50, -56.5, -46.5, -22.1, -2.5, -27.7, -55.7, -76.5).itemStyle().normal().lineStyle().shadowColor("rgba(0,0,0,0.4)");
        option.series(line);
        return option;
    }
}

2. WebView 上启用JavaScript 并注入Java对象:

点击查看全部文件内容

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

推荐阅读更多精彩内容