前言

       对于图例展示,大家有很多不同的用法。同时android也有很多开源图表库(但是很多库都没有维护了),也可以自定义。本文将记录一下如何桥接echarts,作为“源头活水”的echarts使用简单,深受前后端开发者的喜爱。

1.向Echarts扔什么数据?

1.1各种各样的图例,都有相通的数据块,Echarts主要使用是Json数据格式,主要两大部分:legend,series。还有同级的见下表

名称

描述

{color}backgroundColor

全图默认背景,(详见backgroundColor),支持rgba,默认为无,透明

{Array} color

数值系列的颜色列表,(详见color),可配数组,eg:['#87cefa', 'rgba(123,123,123,0.5)','...'],当系列数量个数比颜色列表长度大时将循环选取

{boolean}renderAsImage

非IE8-支持渲染为图片,(详见renderAsImage)

{boolean} calculable

是否启用拖拽重计算特性,默认关闭,(详见calculable,相关的还有 calculableColor, calculableHolderColor, nameConnector, valueConnector)

{boolean} animation

是否开启动画,默认开启,(详见 animation,相关的还有 addDataAnimation, animationThreshold, animationDuration, animationDurationUpdate ,animationEasing)

{Object} timeline

时间轴(详见timeline),每个图表最多仅有一个时间轴控件

{Object} title

标题(详见title),每个图表最多仅有一个标题控件

{Object} toolbox

工具箱(详见toolbox),每个图表最多仅有一个工具箱

{Object} tooltip

提示框(详见tooltip),鼠标悬浮交互时的信息提示

{Object} legend

图例(详见legend),每个图表最多仅有一个图例,混搭图表共享

{Object} dataRange

值域选择(详见dataRange),值域范围

{Object} dataZoom

数据区域缩放(详见dataZoom),数据展现范围选择

{Object} roamController

漫游缩放组件(详见roamController),搭配地图使用

{Object} grid

直角坐标系内绘图网格(详见grid)

{Array | Object} xAxis

直角坐标系中横轴数组(详见xAxis),数组中每一项代表一条横轴坐标轴,标准(1.0)中规定最多同时存在2条横轴

{Array | Object} yAxis

直角坐标系中纵轴数组(详见yAxis),数组中每一项代表一条纵轴坐标轴,标准(1.0)中规定最多同时存在2条纵轴

{Array} series

驱动图表生成的数据内容(详见series),数组中每一项代表一个系列的特殊选项及数据

1.2 以上可选项都是按需配置的。了解数据内容后,再来了解需要封装的JSON数据格式:

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

1.3 在android端装配数据的工作已经有现有的库实现了:com.github.abel533:ECharts:3.0.0.2,但是年代久远,有很多属性没有集成进去。  但是可以将库下载下来自己改造。以下为android端封装option:

val option = GsonOption()
        option.title().text("总额").left(X.center).top("30%")

        option.legend().data = xValues
        option.tooltip().trigger(Trigger.axis)

        val pie = Pie()
 
        pie.avoidLabelOverlap(true)
           .itemStyle().normal().lineStyle()
           .shadowColor("rgba(0,0,0,0.4)")
        pie.type(SeriesType.pie)
        pie.data = yValues
        option.series(pie)

2.数据的传递与解析

2.1 echarts是js造的,android需要使用webView加载静态HTML,进而引用echarts.min.js.现在的问题是将数据传递给静态的HTML,当然后端可以通过jQuery或Ajax方法请求回传。android端可以先加载HTML静态网页,然后在态网页加载完毕后刷新数据,使用loadUrl执行js函数带参,在静态HTML中使用js进行解析。

String optionString = option.toString();
        String call = "javascript:loadEcharts('" + optionString + "')";
        loadUrl(call);

2.2数据解析(js)

function loadEcharts(echartJson){
                var option = JSON.parse(echartJson);
                if (option &&typeof option ==="object") {
                    myChart.setOption(option,true);
                }
            }

3.事件交互

   如何将js的事件调用native方法呢,有三种可以参考。我们还是选择@JavascriptInterface即可快速实现。

4.快速整合

 

配置ECharts

  • 下载Echarts。你可以根据你的需求在ECharts官网下载需要的ECharts组件。我这里选择的是完整版。
  • 将下载好的echarts.min.js文件放入工程中assets目录下。如果没有assets目录,可以先在mian目录下,通过右击 new -> Folder -> Assets Folder 创建。

assets.png

  • 编写echarts.html文件,并将echarts.html放入assets目录。

 

<!DOCTYPE html>
<html style="height: 100%">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8">
    </head>
    <body style="height: 100%; margin: 0">
        <div id="container" style="height: 100%"></div>
        <script type="text/javascript" src="./echarts.min.js"></script>
        <script type="text/javascript">
            var dom =document.getElementById("container");
            var myChart =echarts.init(dom);
            var app ={};
            function loadEcharts(echartJson){
                var option = JSON.parse(echartJson);
                if (option &&typeof option ==="object") {
                    myChart.setOption(option,true);
                }
            }
        </script>
    </body>
</html>

依赖EChart java 对象库

注意:因为该对象库依赖Gson,所以project同样需要添加Gson依赖

 

dependencies {
    implementation 'com.github.abel533:ECharts:3.0.0.2'
    implementation 'com.google.code.gson:gson:2.8.1'
}

代码实现

因为Echarts需要在WebView中显示,所以我们直接自定义一个EchartView继承自WebView用来显示图表。

 

public class EchartView extends WebView {
    private static final String TAG = EchartView.class.getSimpleName();

    public EchartView(Context context) {
        this(context, null);
    }

    public EchartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public EchartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        WebSettings webSettings = getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        webSettings.setSupportZoom(false);
        webSettings.setDisplayZoomControls(false);
        loadUrl("file:///android_asset/echarts.html");
    }

    /**刷新图表
     * java调用js的loadEcharts方法刷新echart
     * 不能在第一时间就用此方法来显示图表,因为第一时间html的标签还未加载完成,不能获取到标签值
     * @param option
     */
    public void refreshEchartsWithOption(GsonOption option) {
        if (option == null) {
            return;
        }
        String optionString = option.toString();
        String call = "javascript:loadEcharts('" + optionString + "')";
        loadUrl(call);
    }
}

再定义一个工具类用来将数据封装为option,这里只封装了一个简单的折线图做例子。
更多图表的封装请参照EChart java 对象库和ECharts官方例子。

 

public class EchartOptionUtil {

    public static GsonOption getLineChartOptions(Object[] xAxis, Object[] yAxis) {
        GsonOption option = new GsonOption();
        option.title("折线图");
        option.legend("销量");
        option.tooltip().trigger(Trigger.axis);

        ValueAxis valueAxis = new ValueAxis();
        option.yAxis(valueAxis);

        CategoryAxis categorxAxis = new CategoryAxis();
        categorxAxis.axisLine().onZero(false);
        categorxAxis.boundaryGap(true);
        categorxAxis.data(xAxis);
        option.xAxis(categorxAxis);

        Line line = new Line();
        line.smooth(false).name("销量").data(yAxis).itemStyle().normal().lineStyle().shadowColor("rgba(0,0,0,0.4)");
        option.series(line);
        return option;
    }
}

在Acitvity中显示
activity_main.xml

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.ming.echartsforandroid.MainActivity">

    <com.example.ming.echartsforandroid.EchartView
        android:id="@+id/lineChart"
        android:layout_width="400dp"
        android:layout_height="400dp"
        android:layout_gravity="center">
    </com.example.ming.echartsforandroid.EchartView>

</LinearLayout>

MainActivity .java

 

public class MainActivity extends AppCompatActivity {
    private EchartView lineChart;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lineChart = findViewById(R.id.lineChart);
        lineChart.setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //最好在h5页面加载完毕后再加载数据,防止html的标签还未加载完成,不能正常显示
                refreshLineChart();
            }
        });
    }

    private void refreshLineChart(){
        Object[] x = new Object[]{
                "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
        };
        Object[] y = new Object[]{
                820, 932, 901, 934, 1290, 1330, 1320
        };
        lineChart.refreshEchartsWithOption(EchartOptionUtil.getLineChartOptions(x, y));
    }

}