一、前言
曲线图标在大多数场景下让数据看起来更为直观,特别是走势曲线的研究对业务有着举足轻重的作用,N年前,自定义布局,绘制曲线图标,K线图,感觉很好玩,也很有趣,想着用Compose实现一把,原来实现起来比原生绘制起来简单多了,但是计算原理其实都差不多。
二、使用WXChart
1、repositories
中添加如下maven
repositories {
maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/releases/' }
}
}
2、 dependencies
中添加依赖
implementation("io.github.wgllss:Wgllss-WXChart:1.0.03")
3、使用地方 主要调用: realDrawChart(this@Canvas, width, height, it, textMeasurer, touchIndex, isTouchLast)
如下:
@Composable
fun LineChart(innerPadding: PaddingValues, viewModel: SampleViewModel = SampleViewModel().apply { setData() }) {
var height by remember { mutableStateOf(0f) }//绘制图表高度
var width by remember { mutableStateOf(0f) } //绘制图表高度
var touchIndex by remember { mutableStateOf(-1) }//点击touch 算出水平数据索引
var isTouchLast by remember { mutableStateOf(false) } // 控制点击绘制浮层,图标最右边时候,可显示在左边
val textMeasurer = rememberTextMeasurer()
val chatModel by viewModel.chatModel.observeAsState()
chatModel?.let {
Canvas(modifier = Modifier
.padding(innerPadding)
.fillMaxWidth()
.height(300.dp)
.onSizeChanged {
width = it.width.toFloat()
height = it.height.toFloat()
}
//监听手势缩放
.graphicsLayer()
.background(Color.White)
.pointerInput(Unit) {
detectTapGestures(onTap = {
touchIndex = getTouchIndex(chatModel, width, it.x, it.y)
isTouchLast = if (chatModel != null) {
chatModel!!.xCount - 3 <= touchIndex
} else false
})
}) {
realDrawChart(this@Canvas, width, height, it, textMeasurer, touchIndex, isTouchLast)
}
}
}
4、数据提供方
private val _datas = MutableLiveData<ChatModel>()
val chatModel: LiveData<ChatModel> = _datas
fun setData() {
val chatLineBean1 = ChatLineBean(getRandomList(), Color.Red, "收藏")
val chatLineBean2 = ChatLineBean(getRandomList(), Color.Magenta, "点赞") //曲线数据,曲线颜色
val chatLineBean3 = ChatLineBean(getRandomList(), Color.Blue, "评论")//曲线数据,曲线颜色
val chatLineBean4 = ChatLineBean(getRandomList(), Color.Green, "阅读")//曲线数据,曲线颜色
val chatmodel = ChatModel(
datas = mutableListOf(chatLineBean1, chatLineBean2, chatLineBean3, chatLineBean4), //多条曲线集
listX = getXlables(), //x轴上刻度文字
yCount = 5, //y轴横线刻度数 ,包含 0,比如0到5 含X轴6条水平
xCount = getXlables().size, //x轴纵向上点数 包含 0 一般为X数据集size 必须大于1
offsetx = toDp(72f), //UI上原点左下角 x偏移
offsetxLable = toDp(12f),//原点 y轴上面刻度文字x偏移 相对控件最左边偏移
offsety = toDp(30f), //UI上原点左下角 y 偏移
offsetyLable = toDp(8f),//原点 y上面刻度文字文字 y偏移 相对控件左下角点,调整Y值文字在竖直中间位置 与横线对齐
xLableStep = 2, //x轴上刻度对应文字,太多了显示不下,可以设置显示步长。如隔4个显示一个
isShowYLine = false,//是否显示Y轴线
clickLayerColor = Color(0x30000000) //点击后展示浮层背景颜色
)
_datas.value = chatmodel
}
5、数据说明(ChartModel的参数
)
参数 | 类型 | 说明 |
---|---|---|
datas | MutableList<ChatLineBean> | 多条曲线集 |
listX | MutableList<String> | x轴上刻度文字 |
yCount | Int | y轴横线刻度数 ,包含 0,比如0到5, 含X轴6条水平线 |
xCount | Int | //x轴纵向上点数 包含 0 一般为X数据集size 必须大于1 |
offsetx | Float | UI上原点左下角 x偏移 |
offsetxLable | Float | 原点 y轴上面刻度文字x偏移 相对控件最左边偏移 |
offsety | Float | UI上原点左下角 y 偏移 |
offsetyLable | Float | 原点 y上面刻度文字文字 y偏移 相对控件左下角点,调整Y值文字在竖直中间位置 与横线对齐 |
xLableStep | Int | x轴上刻度对应文字,太多了显示不下,可以设置显示步长。如隔4个显示一个 |
isShowYLine | Boolean | 否显示Y轴线 |
clickLayerColor | @StableColor | 点击后展示浮层背景颜色 |
6、数据对象ChatLineBean
的参数说明
参数 | 类型 | 说明 |
---|---|---|
listY | MutableList<Float> | 曲线的y值数据集 |
color | @StableColor | 曲线颜色 |
lineTitle | String | 曲线名称 比如 收藏曲线 点赞曲线 |
三、绘制原理
- 主要使用的
drawLine
,drawText
,drawPath
,drawOval
,drawRect
等绘制方法 - 绘制过程中的起始点x,y坐标,是以控件左上角为原来,x轴向右、y轴向下为正方向的 但是图表上UI上的原点是左下角原点。
- 主要的难点在于计算绘制的起始位置,确定UI图表上面的原点位置, 坐标位置计算:
全是初中坐标知识
3.1 我们需要计算图表控件的宽高
(width , height)
,UI图标原点距离左下角的偏移位置(offsetx , offsety)
即为原点。 图表上面距离顶部设定也为offsety
,右边距离控件右边偏移为offsetx/2
3.2 原点位置可以得到坐标为(offsetx , height-offsety)
3.3 X轴最右边坐标为(width- offsetx/2 , height-offsety)
3.4 Y轴最上边坐标为(offsetx , offsety)
3.5 X轴上面假设定0~9的刻度xCount=10
个数据,相邻2个数据之间间隔x值宽度为val xDiv = (width - 1.5f X offsetx) / (xCount - 1)
3.6 X轴上第1,2,3,4...刻度值的X坐标可以得到:offsetx + i X xDiv
(其中:i为x轴数据索引位置,从左到右
)
3.7 Y轴上面yCount
设置为5
, 含X轴6条水平线
,相邻两条高度间隔坐标y值:val heightDiv = (height - 2 X offsety) / yCount
3.8 Y轴上第1,2,3,4...刻度值的Y坐标可以得到:height - offsety - i X heightDiv
(其中:i为y轴刻度线条索引位置,从上到下
)
3.9 找出所有数据中的最大值maxY
,该值对应UI上面Y轴最上面的y坐标
3.10val yValue = it.maxY / (it.yCount)
即是Y轴上刻度间隔对应的实际值
3.11 从下到上每一条横线刻度值:i * yValue
(其中:i为y轴刻度数位置,从下到上
)
3.12 Y轴上面刻度文案坐标便可以计算出来:(offsetxLable, height - it.offsety - i X heightDiv - offsetyLable)
(其中:i为y轴刻度数位置,从下到上
)
3.13 数据最大值和图标Y轴坐标y值对应的比例:val yAbs = (height - 2 X offsety) / maxY
3.14 每一条实际数据
对应图表上面的Y坐标
便可以计算出来:height - item X yAbs - offsety
(其中item:为实际曲线的数据值)
总结
- 本文主要介绍了开源库WXChart的使用及各个参数的配置说明
- 讲述了Compose绘制基础,及相关用法,重点对绘制过程中坐标体系的计算进行了详细分析