Github-hellocharts

探讨向

使用方式

  • 导入库

build.gradle中加入compile 'com.github.lecho:hellocharts-library:1.5.8@aar'


  • 简单折线图的使用方式

布局

在布局文件中加入

<lecho.lib.hellocharts.view.LineChartView 
 
 
 

   android:id="@+id/hello_chart_view" 
  
 android:layout_width="match_parent" 
  
 android:layout_height="wrap_content" />

创建一个图表:

实例化对象:

lineChartView = (LineChartView) findViewById(R.id.line_chart_view);

android图表控件列表 android 图表库_List

那么LineChartData中的数据该如何添加呢?创建一个LineChartData对象data,如图:

android图表控件列表 android 图表库_HelloCharts_02

android图表控件列表 android 图表库_HelloCharts_03

可以发现,有两种方式构建data:

第一种是直接在data的构造方法中添加一个List<Line>对象;

第二种是通过data.setLines(List<Line>)方法设置Lines。

Lines就是图表中的折线对象了!先创建一个Line对象line,再创建一个List<Line> 对象lines,并将line添加到这个List中。然后调用data.setLines(lines)设置折线。

android图表控件列表 android 图表库_List_04

构建Line:

android图表控件列表 android 图表库_android图表控件列表_05

Line的构造方法中可以传入一个List<PointValue>的参数,这个PointValue即是一个点的值了!也就是说,创建一个PointValue对象,就是创建了一个坐标点。而将包括了多个点的List传入Line中,就构建了一条折线!这不就是和手绘折线图的过程一样吗?好,那么创建几个坐标点:

android图表控件列表 android 图表库_Android_06

可以看到,PointValue构造方法中有一个PoindValue(float x, float y),参数即是这个点的横纵坐标。创建3个点,并添加到pointValueList中:

PointValue p1 = new PointValue(1, 4);        PointValue p2 = new PointValue(2, 3);        PointValue p3 = new PointValue(3, 5);        List<PointValue> pointValueList = new ArrayList<>();        pointValueList.add(p1);        pointValueList.add(p2);        pointValueList.add(p3);


好了,现在3个点已经构建完毕。整理一下代码:

void initChart() {        // 创建3个坐标点        PointValue p1 = new PointValue(1, 4);        PointValue p2 = new PointValue(2, 3);        PointValue p3 = new PointValue(3, 5);        List<PointValue> pointValueList = new ArrayList<>();        pointValueList.add(p1);
        pointValueList.add(p2);
        pointValueList.add(p3);

        // 通过坐标点创建出一根折线
        Line line = new Line(pointValueList);
        List<Line> lines = new ArrayList<>();
        lines.add(line);

        // 创建LineChartData对象,并通过setLines方法将只包含了一根折线的列表传入
        LineChartData data = new LineChartData();
        data.setLines(lines);

        // 实例化LineChartView,并传入数据data
        LineChartView lineChartView = (LineChartView) findViewById(R.id.line_chart_view);
        lineChartView.setLineChartData(data);
    }


最后在onCreate方法中调用initChart()方法进行初始化,看看效果:

android图表控件列表 android 图表库_Android_07

发现,只有折线,少了坐标轴啊!那么继续,建立坐标轴:

在HelloCharts中,坐标轴是用Axis对象表示的。

在lineChartView.setLineChartData(data)语句之前,先创建两个Axis对象,axisX和axisY,分别表示X轴和Y轴。然后将其加入到data中。在data中,横纵坐标均有两种添加方式可以选择,分别代表横坐标位于上或下,以及纵坐标位于左或右。这里选择纵坐标在左边,横坐标在下方。

// 创建坐标轴 Axis axisX = new Axis(); Axis axisY = new Axis(); // 将坐标轴传入到data中 data.setAxisXBottom(axisX); data.setAxisYLeft(axisY);
再看看效果:

android图表控件列表 android 图表库_HelloCharts_08

可以看到,一个折线图已经基本完成了!最后再设置一下坐标的属性:

axisX.setTextColor(Color.BLACK); axisX.setName("横坐标"); axisY.setTextColor(Color.BLACK); axisY.setName("纵坐标");
最终效果:

void initChart() {        // 创建3个坐标点        PointValue p1 = new PointValue(1, 4);        PointValue p2 = new PointValue(2, 3);        PointValue p3 = new PointValue(3, 5);        List<PointValue> pointValueList = new ArrayList<>();        pointValueList.add(p1);        pointValueList.add(p2);        pointValueList.add(p3);

        // 通过坐标点创建出一根折线
        Line line = new Line(pointValueList);
        line.setColor(Color.BLACK);
        List<Line> lines = new ArrayList<>();
        lines.add(line);

        // 创建LineChartData对象,并通过setLines方法将只包含了一根折线的列表传入
        LineChartData data = new LineChartData();
        data.setLines(lines);

        // 创建坐标轴
        Axis axisX = new Axis();
        Axis axisY = new Axis();

        axisX.setTextColor(Color.BLACK);
        axisX.setName("横坐标");
        axisY.setTextColor(Color.BLACK);
        axisY.setName("纵坐标");

        // 将坐标轴传入到data中
        data.setAxisXBottom(axisX);
        data.setAxisYLeft(axisY);

        // 实例化LineChartView,并传入数据data
        LineChartView lineChartView = (LineChartView) findViewById(R.id.line_chart_view);
        lineChartView.setLineChartData(data);
    }



android图表控件列表 android 图表库_图表_09



  • 进阶设置:坐标轴和Viewport

在使用的过程中我发现,如果数据过多,折线会全部在屏幕上挤成一团,非常不美观,需要放大之后才能看清楚。

比如我要做一个x轴为日期,y轴为访问量的图表,一共150个数据,代码和结果如下所示:

void buildChartTotal() {
        List<String> dateList = new ArrayList<>();
        List<Integer> visitorNumList = new ArrayList<>();
        for (String[] strs : dailyDataSplit) {
            String sDate = strs[1] + "/" + strs[2];
            int sVisitorNum = Integer.parseInt(strs[3]);
            if (!dateList.contains(sDate)) {
                dateList.add(sDate);
                visitorNumList.add(sVisitorNum);
            }
        }

        List<AxisValue> axisXValueList = new ArrayList<>();
        List<PointValue> pointValueList = new ArrayList<>();

        for (int i = 0; i < dateList.size(); i++) {
            axisXValueList.add(new AxisValue(i).setLabel(dateList.get(i)));

            pointValueList.add(new PointValue(i, visitorNumList.get(i)));
        }

        Axis axisX = new Axis(axisXValueList);
        axisX.setTextColor(R.color.dark_gray);
        axisX.setName("日期");
        axisX.setHasLines(true);
        Axis axisY = new Axis();
        axisY.setValues(axisYValueList);
        axisY.setTextColor(R.color.dark_gray);
        axisY.setName("访问总人数");


        Line line = new Line(pointValueList);
        line.setColor(R.color.dark_gray);
        line.setHasLabels(true);
        List<Line> lines = new ArrayList<>();
        lines.add(line);

        LineChartData lineChartData = new LineChartData(lines);
        lineChartData.setAxisXBottom(axisX);
        lineChartData.setAxisYLeft(axisY);

        lineChartView.setZoomType(ZoomType.HORIZONTAL);
        lineChartView.setInteractive(true);
        lineChartView.setLineChartData(lineChartData);
    }

android图表控件列表 android 图表库_Android_10

显然,这样的显示效果并不好。考虑到以下问题:

1. 同时显示的数据太多以至于产生重叠;

2. 坐标轴上面也不需要这么多的标签;

3. 折线的最底部抵在了x轴上面,顶部顶在图表的最上方,我希望上下有一些空白的空间。

所以,这时候需要设置图表中显示的数据范围,减少坐标轴上Label的个数。

具体的做法是使用Viewport:

先看看Viewport的说明:

android图表控件列表 android 图表库_HelloCharts_11

一个Viewport对象包含了4个公开的float类型成员:top,bottom,left,right;通过这4个变量可以设定出该Viewport的上下左右边界。

在lineChartView中有以下4个方法:

getCurrentViewport():获取当前图表的Viewport。

setCurrentViewport(Viewport):设置当前图表的Viewport。即是设置图表的可见部分的边界。

getMaximumViewport():设置图表的最大Viewport。

setMaximumViewport(Viewport):设置图表的最大Viewport。即是设置图表在缩放之后可达到的最外层边界,使用setCurrentViewport也无法超过该范围。

通过使用Viewport来设定显示范围。

1. 在lineChartView.setLineChartData(lineChartData)这条语句之后,通过:

Viewport maxViewport = lineChartView.getMaximumViewport(); 来得到maxViewport。

2. 新建一个Viewport对象:

Viewport viewport = new Viewport(); 

3. 对viewport的上下左右4个成员进行赋值。

注意这个viewport的边界是 不能超过maxViewport的,而因为希望上下有空白空间,所以竖直方向需要增加高度,所以要先改变maxViewport的top和bottom,让最外层的高度增加:

maxViewport.bottom = maxViewport.bottom - 5;
maxViewport.top = maxViewport.top + 5;

然后对viewport的上下边界赋值:

viewport.top = maxViewport.top;

viewport.bottom = maxViewport.bottom;

接下来,假设当前图表要显示最新的8个数据,那么:

viewport.right = maxViewport.right;
viewport.left = maxViewport.right - 7;

这样要想要的viewport就设定好了。最后再调用:

lineChartView.setCurrentViewport(viewport);

就设置好了当前图表显示内容了。

设置Y轴Label的个数

因为Axis的实例中有一个setValues(List<AxisValue> values)方法可以设置坐标轴上标记的值,而只要屏幕显示的下,这个values的size就是坐标轴标签的个数。于是通过这个方法就可以减少y轴标签的密度了,非常简单。

/**     * 最终代码:创建图表
     */
    void buildChartTotal() {
        // 初始化数据列表
        List<String> dateList = new ArrayList<>();
        List<Integer> visitorNumList = new ArrayList<>();
        for (String[] strs : dailyDataSplit) {
            String sDate = strs[1] + "/" + strs[2];
            int sVisitorNum = Integer.parseInt(strs[3]);
            if (!dateList.contains(sDate)) {
                dateList.add(sDate);
                visitorNumList.add(sVisitorNum);
            }
        }

        List<AxisValue> axisXValueList = new ArrayList<>();
        List<AxisValue> axisYValueList = new ArrayList<>();
        List<PointValue> pointValueList = new ArrayList<>();

        for (int i = 0; i < dateList.size(); i++) {
            axisXValueList.add(new AxisValue(i).setLabel(dateList.get(i)));
            pointValueList.add(new PointValue(i, visitorNumList.get(i)));
        }
        // 设置y轴的标签
        axisYValueList = createYValue(visitorNumList);

        // 设置坐标轴属性
        Axis axisX = new Axis(axisXValueList);
        axisX.setTextColor(R.color.dark_gray);
        axisX.setName("日期");
        axisX.setHasLines(true);
        Axis axisY = new Axis();
        axisY.setValues(axisYValueList);
        axisY.setTextColor(R.color.dark_gray);
        axisY.setName("访问总人数");

        // 创建折线
        final Line line = new Line(pointValueList);
        line.setColor(R.color.dark_gray);
        line.setHasLabels(true);
        List<Line> lines = new ArrayList<>();
        lines.add(line);

        // 创建图标数据
        final LineChartData lineChartData = new LineChartData(lines);
        lineChartData.setAxisXBottom(axisX);
        lineChartData.setAxisYLeft(axisY);

        lineChartView.setZoomType(ZoomType.HORIZONTAL);
        lineChartView.setInteractive(true);
        lineChartView.setLineChartData(lineChartData);

        // 设置viewport
        Viewport maxViewport = lineChartView.getMaximumViewport();
        maxViewport.bottom = maxViewport.bottom - 5;
        maxViewport.top = maxViewport.top + 5;
        maxViewport.right = maxViewport.right + 0.2f;// 解决最右边的数据可能显示不完全的问题
        Viewport viewport = new Viewport(maxViewport);
        viewport.left = maxViewport.right - 7.8f;
        lineChartView.setCurrentViewport(viewport);

        // 点击显示/隐藏折线上显示的数据
        btnSetVisibility.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (line.hasLabels()) {
                    line.setHasPoints(false);
                    line.setHasLabels(false);
                } else {
                    line.setHasLabels(true);
                    line.setHasPoints(true);
                }
                // 刷新显示
                lineChartView.setCurrentViewport(lineChartView.getCurrentViewport());
            }
        });
    }

    List<AxisValue> createYValue(List<Integer> visitNums) {
        int max = visitNums.get(0), min = max;
        for (int i : visitNums) {
            if (i > max) {
                max = i;
            } else if (min > i) {
                min = i;
            }
        }
        max += 5;
        min -= 5;
        List<AxisValue> axisValueList = new ArrayList<>();
        for (int i = min; i < max; i += (max - min) / 20 + 1) {
            axisValueList.add(new AxisValue(i).setLabel(String.valueOf(i)));
        }
        return axisValueList;
    }



显示效果:


android图表控件列表 android 图表库_android图表控件列表_12


android图表控件列表 android 图表库_HelloCharts_13