Compose曲线图表库WXChart,你只需要提供数据配置就行了

803 阅读5分钟

img_v3_02gp_14677f22-beba-45ff-8d6f-bf564839858g.jpg

一、前言

曲线图标在大多数场景下让数据看起来更为直观,特别是走势曲线的研究对业务有着举足轻重的作用,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的参数

参数类型说明
datasMutableList<ChatLineBean>多条曲线集
listXMutableList<String>x轴上刻度文字
yCountInty轴横线刻度数 ,包含 0,比如0到5, 含X轴6条水平线
xCountInt//x轴纵向上点数 包含 0 一般为X数据集size 必须大于1
offsetxFloatUI上原点左下角 x偏移
offsetxLableFloat原点 y轴上面刻度文字x偏移 相对控件最左边偏移
offsetyFloatUI上原点左下角 y 偏移
offsetyLableFloat原点 y上面刻度文字文字 y偏移 相对控件左下角点,调整Y值文字在竖直中间位置 与横线对齐
xLableStepIntx轴上刻度对应文字,太多了显示不下,可以设置显示步长。如隔4个显示一个
isShowYLineBoolean否显示Y轴线
clickLayerColor@StableColor点击后展示浮层背景颜色

6、数据对象ChatLineBean的参数说明

参数类型说明
listYMutableList<Float>曲线的y值数据集
color@StableColor曲线颜色
lineTitleString曲线名称 比如 收藏曲线 点赞曲线

三、绘制原理

  1. 主要使用的 drawLine,drawTextdrawPath,drawOval,drawRect 等绘制方法
  2. 绘制过程中的起始点x,y坐标,是以控件左上角为原来,x轴向右、y轴向下为正方向的 但是图表上UI上的原点是左下角原点。
  3. 主要的难点在于计算绘制的起始位置,确定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.10 val 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:为实际曲线的数据值)

总结

  1. 本文主要介绍了开源库WXChart的使用及各个参数的配置说明
  2. 讲述了Compose绘制基础,及相关用法,重点对绘制过程中坐标体系的计算进行了详细分析
github地址
gitee地址

感谢阅读:

欢迎 关注,点赞、收藏

这里你会学到不一样的东西