• Android 图表开源库调研及使用示例


    本文为作者原创,允许转载,不过请在文章开头明显处注明链接和出处!!! 谢谢配合~
    作者:stars-one
    链接:https://www.cnblogs.com/stars-one/p/17889588.html

    本篇大约有8644个字,阅读预计需要10.80分钟


    原文地址: Android图表开源库调研及使用示例 - Stars-One的杂货小窝

    之前做的几个项目都是需要实现图表统计展示,于是做之前调研了下,做下记录

    概述

    目前用的就是AAChartCore-Kotlin这个库

    还有些其他的,没细看了,链接贴出来:

    AAChartCore-Kotlin

    基于hcharts这个js库整的图表库,所以如果有不能实现的效果,可以先去看下js库的实现

    实质上Android库只是封装了对应的实体类,之后也是会将实体类转为json配置,从而让js库绘制出图表

    折线图实现示例

    效果:

    <com.github.aachartmodel.aainfographics.aachartcreator.AAChartView
    	android:id="@+id/aa_chart_view"
    	android:layout_width="match_parent"
    	android:layout_height="match_parent">
    
    com.github.aachartmodel.aainfographics.aachartcreator.AAChartView>
    
    val arrayData = arrayOf(
    	AASeriesElement()
    		.name("Tokyo")
    		.color("#e5473d")
    		.data(arrayOf(86,125,112,168,123,131,119,95,112,86)),
    	AASeriesElement()
    		.name("NewYork")
    		.color("#40a0e2")
    		.data(arrayOf(42,89,76,126,87,91,73,67,80,110)),
    	AASeriesElement()
    		.name("London")
    		.color("#0bb142")
    		.data(arrayOf(40,78,62,83,58,67,31,53,68,74)),
    )
    
    
    
    val aaChartModel = AAChartModel()
    	.chartType(AAChartType.Spline)
    	.backgroundColor("#2f2f2f")
    	.dataLabelsEnabled(false)
    	.markerSymbol(AAChartSymbolType.Circle)
    	.zoomType(AAChartZoomType.X)
    	.series(arrayData)
    	.categories(arrayOf(
    		"5.19",
    		"5.20",
    		"5.21",
    		"5.22",
    		"5.23",
    		"5.24",
    		"5.25",
    		"5.26",
    		"5.27",
    		"5.28",
    	))
    
    /*图表视图对象调用图表模型对象,绘制最终图形*/
    binding.aaChartView.aa_drawChartWithChartModel(aaChartModel)
    

    有两种绘制数据的方法:

    • aa_drawChartWithChartModel(AAChartModel)
    • aa_drawChartWithChartOptions(AAOptions)

    AAChartModel可以转为AAOptions,通过aa_toAAOptions()方法

    说明

    AAOptions实际上就是官方对应的json数据格式,如果需要自定义设置,可以参考官方的API文档,对AAOptions里的数据进行修改

    // 图表配置
    var options = {
    	chart: {
    		type: 'bar'                          //指定图表的类型,默认是折线图(line)
    	},
    	title: {
    		text: '我的第一个图表'                 // 标题
    	},
    	xAxis: {
    		categories: ['苹果', '香蕉', '橙子']   // x 轴分类
    	},
    	yAxis: {
    		title: {
    			text: '吃水果个数'                // y 轴标题
    		}
    	},
    	series: [{                              // 数据列
    		name: '小明',                        // 数据列名
    		data: [1, 0, 4]                     // 数据
    	}, {
    		name: '小红',
    		data: [5, 7, 3]
    	}]
    };
    // 图表初始化函数
    var chart = Highcharts.chart('container', options);
    

    上面的options变量,就是对应的AAOptions这个实体类(转换json的操作不需要我们去做)

    官方demo如何参考?

    首先,我们到此网站Highcharts 演示 | Highcharts,找到一个符合我们需要的基本图表,比如说我找了个基础折线图 | Highcharts

    之后可以看到,下面有个编辑源代码的功能,点击进去会进入到一个在线运行js代码的网站

    此时,我们再打开Highcharts JS API 文档,对demo进行样式上的修改,最终得到我们需要的js代码

    之后参考js代码,来进行我们AAChartCore-Kotlin的代码配置设置AAOptions即可

    当然,建议还是先看一遍官方文档,比如这个文章图表主要组成 | Highcharts 使用教程,可以知道图表的基本组成及一些通用名称,这样后面去找api文档也比较方便

    AAChartCore-Kotlin封装的时候,可能有些属性没有考虑到,所以这个时候我们没法通过官方的属性来进行设置,而且官方的很多配置类都是final类型,没有open关键字,导致我们需要去修改源码

    于是我就是给开发者提了几个pull request,虽然都被接受合并了,不过开发者什么时候发个版本不确定,于是我就fork一份,自行改了并发布JitPack(各位有需要可以使用我的版本)

    版本也没什么大改动,只是改了下某些类的开放性,方便继承扩展其他属性字段,依赖如下:

    implementation 'com.github.stars-one:AAChartCore-Kotlin:1.0'
    

    左右滑动的实现

    也是看了半天的js库的文档和尝试,才实现的效果

    //这几个是数据
    val arrayData = arrayOf(
    	AASeriesElement()
    		.color("#e5473d")
    		.data(sysArr),
    	AASeriesElement()
    		.color("#40a0e2")
    		.data(diaArr),
    	AASeriesElement()
    		.color("#0bb142")
    		.data(pulesArr),
    )
    //构造绘制的model
    val aaChartModel = AAChartModel()
    	.chartType(AAChartType.Spline)
    	.backgroundColor("#2f2f2f")
    	.dataLabelsEnabled(false)
    	.markerSymbol(AAChartSymbolType.Circle)
    	.zoomType(AAChartZoomType.X)
    	.categories(categoriesArr)
    	.series(arrayData)
    	.yAxisVisible(true)
    	.touchEventEnabled(false)
    	.tooltipEnabled(false)
    	.legendEnabled(false)
    	.scrollablePlotArea(AAScrollablePlotArea().minWidth(categoriesArr.size*40).scrollPositionX(0))
    

    核心的方法zoomType(AAChartZoomType.X).scrollablePlotArea(AAScrollablePlotArea().minWidth(categoriesArr.size*40).scrollPositionX(0))

    这里要给图表设置个最小宽度才能实现左右滑动,我就以每个数据给了40px的宽度,这里各位可以看情况改

    柱形图(范围)代码示例

    实现效果如下下图:

    private fun initChart() {
    
    	val jsArray = arrayOf(
    		arrayOf(60,130),
    		arrayOf(80,190),
    		arrayOf(60,130),
    		arrayOf(90,160),
    		arrayOf(68,145),
    		arrayOf(75,126),
    		arrayOf(67,139),
    	)
    	val categoriesArr = arrayOf(
    		"5.19",
    		"5.20",
    		"5.21",
    		"5.22",
    		"5.23",
    		"5.24",
    		"5.25"
    	)
    
    	val kotlinArray: Array =
    		jsArray.map { it.map { it.toInt()  }.toTypedArray() }.toTypedArray()
    
    	val arrayData = arrayOf(
    		AASeriesElement()
    			.marker(AAMarker().enabled(false))
    			.data(kotlinArray)
    	)
    
    	val aaChartModel = AAChartModel()
    		.categories(categoriesArr)
    		.legendEnabled(false)
    		.touchEventEnabled(false)
    		.tooltipEnabled(false)
    		.chartType(AAChartType.Columnrange)
    		.xAxisVisible(true)
    		.yAxisVisible(true)
    		.yAxisLabelsEnabled(true)
    		.xAxisLabelsEnabled(true)
    		.backgroundColor("#04081a")
    		.dataLabelsEnabled(false)
    		.gradientColorEnable(true)
    		.borderRadius(25)
    		.markerRadius(25)
    		.series(arrayData)
    
    	val options = aaChartModel.aa_toAAOptions().apply {
    		val list = listOf("#d14664")
    		val colorList = (0..6).map { list.random() }
    
    		yAxis?.apply {
    			//改变y坐标轴的宽度(设置
    			//lineWidth = 0
    			//y坐标轴的颜色
    			//lineColor = "red"
    
    			//y坐标轴的左边文本隐藏
    			title(AATitle().text(""))
    
    			//y坐标轴的水平刻度的样式
    			gridLineColor = "#2b2745"
    			gridLineWidth= 1
    			gridLineDashStyle = AAChartLineDashStyleType.LongDash.value
    			
    			//起始刻度
    			min=30
    			//刻度间隔
    			tickInterval = 30
    		}
    		xAxis?.apply {
    			lineWidth=0
    		}
    
    		plotOptions?.columnrange =
    			AAColumnRange(
    				SizeUtils.dp2px(2f),
    				SizeUtils.dp2px(8f),
    				0,
    				colorList,
    				AAChartLineDashStyleType.Dash
    			)
    	}
    
    
    	/*图表视图对象调用图表模型对象,绘制最终图形*/
    	binding.aaChartView.aa_drawChartWithChartOptions(options)
    
    }
    @Keep	
    data class AAColumnRange(
        /**
         * 柱形图的圆角
         */
        var borderRadius: Number,
        /**
         * 柱形图的宽度
         */
        var pointWidth: Number,
        /**
         * 柱形图的边框宽度
         */
        var borderWidth: Number = 0,
        /**
         * 每个柱形图的颜色
         */
        var colors: List,
        /**
         * 设置为true才会使用上面的颜色数组
         */
        var dashStyle: AAChartLineDashStyleType,
    
        var colorByPoint: Boolean = true,
    )	
    
    

    柱形图渐变色实现

    原仓库是没有封装渐变的属性的,这样我就是参考js代码及对应的文档,整了几个类来实现

    效果图:

    @Keep
    data class AAColumnGradientColor(val linearGradient: LinearGradient, val stops: List>)
    
    @Keep
    data class LinearGradient(val x1: Float, val y1: Float, val x2: Float, val y2: Float)
    
    @Keep
    data class AAColumnRange(
        /**
         * 柱形图的圆角
         */
        var borderRadius: Number,
        /**
         * 柱形图的宽度
         */
        var pointWidth: Number,
        /**
         * 柱形图的边框宽度
         */
        var borderWidth: Number = 0,
        /**
         * 每个柱形图的颜色
         */
        var colors: List,
    
        /**
         * y轴水平刻度线条
         */
        var dashStyle: AAChartLineDashStyleType,
        /**
         * 设置为true才会使用上面的颜色colors数组
         */
        var colorByPoint: Boolean = true,
    
    )
    
    val gradient = AAColumnGradientColor(
    	LinearGradient(0f, 0f, 0f, 1f),
    	listOf(
    		listOf(0, "#fceed3"),    // 颜色的起始位置
    		listOf(1, "#ce395a")     // 颜色的结束位置
    	)
    )
    
    val list = listOf(gradient)
    
    plotOptions?.columnrange =AAColumnRange(
    	SizeUtils.dp2px(2f),
    	SizeUtils.dp2px(8f),
    	0,
    	colorList,
    	AAChartLineDashStyleType.Dash
    )
    

    混淆规则

    # 图表库
    -keep class com.github.aachartmodel.** {*;}
    
    //这个是官方文档上写的混淆规则,如果出现问题可以使用上面这个
    -keep class com.github.aachartmodel.aainfographics.** { *; }
    

    注意:如果使用上面自定义了些字段,对应的类也要添加忽略混淆,不然图表的样式会出现问题,我上面是加了个@Keep注解来忽略

    MPChart

    似乎是开发者要搞收费了,文档都看不到,暂且记录下之前写的一个简单图表demo代码示例

    private fun testDrawChart2() {
    	val chart = binding.mpChart
    
    
    	// 设置 X 轴坐标值
    	val labels = arrayOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
    	val xAxis = chart.xAxis
    	xAxis.valueFormatter = IndexAxisValueFormatter(labels)
    
    
    	// 将数据集添加到数据对象中
    	val lineData = LineData(listOf(
    		createDataSet(),
    		createDataSet()
    	))
    	chart.data = lineData
    
    
    	chart.invalidate()
    
    	val yAxisLeft = chart.axisLeft
    	yAxisLeft.removeAllLimitLines()
    	chart.invalidate()
    
    }
    
    private fun createDataSet(): LineDataSet {
    	// 创建数据点 (日期, 温度)
    	val entries =(0..6).map{
    	   Entry(it.toFloat(),Random.nextInt(0..30).toFloat())
    	}
    	//val entries = listOf(
    	//
    	//    Entry(1f, 27.4f),
    	//    Entry(2f, 28.9f),
    	//    Entry(3f, 29.6f),
    	//    Entry(4f, 25.8f),
    	//    Entry(5f, 26.2f),
    	//    Entry(6f, 30.2f),
    	//    Entry(7f, 31.1f)
    	//)
    
    	// 将数据点添加到数据集中
    	val dataSet = LineDataSet(entries, "")
    
    	dataSet.color = Color.GREEN
    	dataSet.lineWidth = 2f
    	dataSet.setDrawCircles(true)
    
    	//设置每个坐标点的颜色
    	dataSet.setDrawCircleHole(true)
    	dataSet.circleHoleColor = Color.GREEN
    
    	dataSet.circleRadius = 4f
    	dataSet.valueTextSize = 12f
    	//需要曲线
    	dataSet.mode = LineDataSet.Mode.HORIZONTAL_BEZIER
    	return dataSet
    }
    
    /**
     * 图表组件的一些配置
     */
    private fun configChartView() {
    	val chart = binding.mpChart
    	// 显示动画
    	chart.animateXY(1000, 1000)
    
    	// 设置属性
    	chart.description.isEnabled = false
    	chart.setTouchEnabled(true)
    	chart.isDragEnabled = true
    	chart.setScaleEnabled(true)
    	chart.setPinchZoom(true)
    
    	//不显示底部的图例样式
    	chart.legend.form = Legend.LegendForm.NONE
    
    
    	val xAxis = chart.xAxis
    	//设置x坐标在下面(默认是在上面的)
    	xAxis.position = XAxis.XAxisPosition.BOTTOM
    	xAxis.granularity = 1f
    	xAxis.textColor = Color.parseColor("#898989")
    	xAxis.textSize = SizeUtils.dp2px(10f).toFloat()
    
    	// 设置 Y 轴坐标值
    	val yAxisLeft = chart.axisLeft
    	yAxisLeft.setStartAtZero(false)
    	yAxisLeft.setTextColor(Color.parseColor("#898989"))
    	yAxisLeft.setTextSize(SizeUtils.dp2px(10f).toFloat())
    
    	// 创建 LimitLine 对象,并设置相关属性
    	val limitLine = LimitLine(30f, "Threshold")
    	limitLine.lineColor = Color.RED                                   // 设置线条颜色为红色
    	limitLine.lineWidth = 2f                                          // 设置线条宽度为 2 像素
    	limitLine.enableDashedLine(10f,5f,0f)
    
    	// 添加 LimitLine 对象到 YAxis 对象中,并刷新图表
    	yAxisLeft.addLimitLine(limitLine)
    	chart.invalidate()
    
    }
    
  • 相关阅读:
    Prometheus的Pushgateway快速部署及使用
    数据结构——栈与队列
    C++ 基于红黑树的map和set
    grpc和thrift的概念及区别
    计算机的发展史,让你想到了什么?
    C语言——程序环境和预处理
    AWK学习
    20220728使用电脑上的蓝牙和汇承科技的蓝牙模块HC-05配对蓝牙串口传输
    uniapp——列表图片加载太多且空间占用太大的处理方法(降低清晰度)
    最短路相关笔记
  • 原文地址:https://www.cnblogs.com/stars-one/p/17889588.html