全网最火可视化趋势视频实现深度解析,同时新增条形图表

1,453 阅读10分钟

互联网智慧大数据分析,图表,和可视化趋势是一种趋势,分析的利器

可视化图表系列如下:
(一)Compose曲线图表库WXChart,你只需要提供数据配置就行了
(二)Compose折线图,贝赛尔曲线图,柱状图,圆饼图,圆环图。带动画和点击效果
(三)全网最火视频,Compose代码写出来,动态可视化趋势视频,帅到爆
(四)全网最火可视化趋势视频实现深度解析,同时新增条形图表
(五)庆元旦,出排名,手撸全网火爆的排名视频,排名动态可视化
(六)Android六边形战士能力图绘制,Compose实现
(七)Android之中美PK,赛事PK对比图Compose实现
(八)Android之等级金字塔之Compose智能实现

7777.gif

一、前言

前面的文章介绍了折线图、贝塞尔曲线图,柱状图,圆饼图,圆环图,
本文重点介绍:

1. 对之前数据模型配置进行优化整理了一次,本文会详细介绍
2. 这次新增条形图,和动态走势趋势图(可配背景音乐录制成视频
3. 重点解说动态走势趋势图是怎样绘制出来的

二、基本数据模型配置新增内容介绍

配置X轴线颜色:colorXLine
配置Y轴线颜色:colorYLine
图表中刻度线颜色:colorLine (刻度线颜色,可能竖线,也可能是横线,看图表) 刻度线对应文案值文字颜色:colotLable(X轴上面刻度值文案颜色,柱状图,曲线折线图也是Y 轴上面刻度值文案颜色) 点击显示浮层宽度:layerWidth
动画执行时长:durationMillis(动态趋势图是每个数据间隔时间)
动画首次延迟时间:animateDelay

对于圆饼图,圆环图

offsetx:相对图形中心偏移,正数向右,负数向左
offsety:相对图形中心偏移,正数向下,负数向上

对于柱状图,条形图,或者动态图

新增配置:对于第一个和最后一个条形 或柱状,设置距离X轴或者Y轴两端偏移距离
offextBarTopY:顶部第一条bar 距离顶部距离 ,Y轴线距离顶部距离
offextBarBottomY:底部第一条bar 距离底部距离 Y轴线距离底部距离
offextBarRightX:柱状图最后一根距离X轴右边距离
offextBarLeftX:柱状图第一根距离X轴左边边距离
isTop:对于动态趋势图,X轴是否设置到顶部

柱状图,条形图属性介绍:

ChartBarBean:柱状图实体
value:数值
color:条形柱状图颜色
title:条形柱状图颜色

其他相关内容: Compose绘制的坐标体系,及相关计算在 Compose曲线图表库WXChart,你只需要提供数据配置就行了 篇已经介绍过了

其他图表相关点击事件,模型配置在Compose折线图,贝赛尔曲线图,柱状图,圆饼图,圆环图。带动画和点击效果 介绍过了

三、新增条形图表:

先上效果图:
6666.gif 实现原理大致和柱状图差不多,只是从竖向变成了横向
配置数据模型如下:

//条形图
val chatHBarModel = ChartBarModel(getRandomBarList()).apply {
    barWidth = toDp(15f)
    offextBarTopY = toDp(5f)
    offextBarBottomY = toDp(5f)
    yCount = list.size //y轴横线刻度数 ,包含 0,比如0到5 设置为 6
    xCount = 10 //X轴横线刻度数 ,包含 0,比如0到5 设置为 6
    offsetx = toDp(72f) //UI上原点左下角 x偏移
    offsetxLable = toDp(20f)//原点 y轴上面刻度文字x偏移  相对控件最左边偏移
    offsety = toDp(30f) //UI上原点左下角 y 偏移
    offsetyLable = toDp(8f)//原点 y上面刻度文字文字 y偏移 相对控件左下角点,调整Y值文字在竖直中间位置 与横线对齐
    layerWidth = toDp(100f)
}

使用地方调用:realDrawHBarChart如下:


@Composable
fun HBarChart(innerPadding: PaddingValues = PaddingValues(0.dp), viewModel: SampleViewModel = SampleViewModel().apply { setData() }) {
    var touchData by remember { mutableStateOf(Pair(-1, 0f)) }
    var isTouchLast by remember { mutableStateOf(false) }
    val textMeasurer = rememberTextMeasurer()
    val chatModel by viewModel.chatHBarModel.observeAsState()
    chatModel?.let {
        Column(
            modifier = Modifier
                .padding(innerPadding)
                .fillMaxWidth()
                .fillMaxHeight()
        ) {

            val modifier = Modifier
                .fillMaxWidth()
                .height(300.dp)
                .background(Color.White)
                .graphicsLayer()      //监听手势缩放
                .pointerInput(Unit) {
                    detectTapGestures(onTap = { t ->
                        touchData = getTouchHBarIndex(it, size.width.toFloat(), size.height.toFloat(), t.x, t.y)
                        isTouchLast = t.x > size.width.toFloat() - it.offsetx / 2 - it.layerWidth
                    })
                }
            realDrawHBarChart(modifier, textMeasurer, it, touchData, isTouchLast)
        }
    }
}

四、 动态趋势图模型介绍:

DynamicModel:动态数据配置数据模型

参数类型说明
arrayKeyArray存放当前年份特定值,当前年份Key
mapListMutableMap<String, MutableList<DynamicBarBean>>数据集,通过当前年份key查找
mapImageMutableMap<String, DynamicImage>每个条形图的动态图标,可配置网络图片
dynamicChartNameString动态表名称
bgUrlString整个动画背景图
keyTextOffsetXFloat年份相对右下角X偏移
keyTextOffextYFloat年份相对右下角Y偏移
maxValueOffsetRightFloat该值为条形右边文字说明所占有的宽度,因为条形最大长度 = X轴线长度-条形右边文字说明所占有的宽度
musicUrlString背景音乐,可配置网络链接
formatStringString数字格式化设置
multiplierFloat数据显示格式所用的乘数
isPlayCompleteBoolean是否播放完成
isAutoBarWidthBoolean是否自动计算条形宽度,为true时,手动设置barWidth就无效了

DynamicKey:内配置字段:

参数类型说明
currentKeyString当前数据的年份 或者日期,或者其他作为K的值
maxValueFloat当前K值(年份下或日期下)下最大的值
xMaxValueFloat当前x坐标轴上面最大的刻度数值,比maxValue要小

DynamicBarBean:动态条形图数据

参数类型说明
valueFloat条形当前值
colorColor条形颜色
titleString条形名称
diffValueFloat条形下一个值与当前值的差值
currPosInt当前排名位置 list内所在位置,不是排名第几的位置
nextPosInt下一年份排名位置
diffPosIntnextPos - currPos :位置差值

DynamicImage:每个条码对于动态图片配置

参数类型说明
imgUrlString每个条形图可配置的图标地址
bitmapImageBitmap需要绘制的bitmap

五、可视化趋势视频实现深度解析绘制

本文主要讲drawDynamicBarChart内怎么实现的,相关代码在前面文章有介绍,或者对照项目代码可参考:

  1. 首先数据切换是每个年份之间间隔配置动画时间durationMillis,动画结束后从mapListmap中根据通过年份Key取出当前年份下的数据集
  2. 切换Key值是往上加的,可能其他趋势这个类似年份的key不是数字,是月份日期,不用Int型往上加,那样可能还要判断2月28号,29号,30号,31号怎么切换到下一个月份。所以设计成把这个key依次放进数组里面,让数组里面位置往上加,通过位置拿到当前位置下的DynamicKey,这里面存放了当前key,key下的相关最大值,然后通过这个key,去mapListmap中拿取当前数据集
  3. 上面2里面数组里面位置变化就是 var drawPosition by remember { mutableStateOf(0) },可以通过位置拿到当前key:val drawKeyNo = remember(drawPosition) { it.arrayKey[drawPosition].currentKey }
  4. 对于排名第一的就是上面条形最长的,是固定的,这个就是图表控件内可用的最大宽度availableWidth:它是坐标体系下,X轴最大长度,这里注意了,我们配置了:maxValueOffsetRight:条形最大长度+条形右边图表和文案数字变化这和的总宽度,应该为图标宽度-图表左右偏移,即是:val availableWidth = width - 1.5f * it.offsetx - it.maxValueOffsetRight
  5. 上面4里面条形最大长度,对应的当下年份下最大GDP值,我们可以通过事先处理好的模型数据里面 DynamicKey内拿到,但是这个值是变化的,是不停在往上涨的,是怎么变化的呢?其实当在1960年时候,这个变化值是1960年当前值+(1961年-1960年)的差值,这个差值是慢慢逐渐从这个差值的0,变化到差值上限,同理,如果这个差值是负的,也一样逻辑
  6. 5中提到的这个差值,我们在数据模型准备时,先算好,因为每个条形图对应的都有这个差值,而且是每往下一个年份走都有这个差值,所以这个差值放在了条形数据里面DynamicBarBeandiffValue上面
  7. diffValue这个差值怎么搞成动画慢慢变过去?这里用到compose里面的一个动画animateFloatAsState
  8. 但是animateFloatAsState有个问题,比如targetValue设置成100f,执行一次动画结束后它就停留在100f了,它内部是通过remember记住了这个状态的,问题就在这里,比如从1960年动画跑完,这个值停留在100f,我们把年份切换到1961年时再去用它,它就一直是100f,那下一个动画就不能执行了,它没有提供回到初始值的方法,如果把它先设置成0,再设置成100f,它是不会动的,只设置成0,它又要从100f慢慢变成0,这样动画数值变化方向不是反了吗?我们可以再一次执行完,将它设置成0,然后用100f-它,减后的数值就是我们想要的又从0慢慢变成100f了,好了,那这样,这个动画我们通过一个值判断,来回变化,前一次让它0到100,下一次设置成0,然后减它变成我们想要的0到100f
  9. 这样拿到当前变化的最大值val maxX = it.maxValue(drawPosition) + (dList[dList.size - 1].diffValue / 100f) * animateWValue,可以得到X方向可用宽度相对最大值的比例系数:val xAbs = availableWidth / maxX,那么每一个条形数值乘以这个比例系数,就得到条形的UI长度的坐标,因为maxX是变化的,所以得到后的都是变化的,所以每个条形的变化长度为 (item.value + (item.diffValue / 100f) * animateWValue) * xAbs
  10. 条形长度变化搞定了,我们来写每个条形可上下移动,因为排名是变化的,我们在准备模型前要事先把每个年份下条形图做一个排序,记录下当前在list排序位置,同时下一个年份的也做好,位置排序差值我们事先算好,记录在每个条形上面:如:
class DynamicBarBean(
    var value: Float,          //条形当前值
    @Stable val color: Color,  //条形颜色
    val title: String          //条形名称
) {
    var diffValue: Float = 0f  // 条形下一个值与当前值的差值
    var currPos: Int = 0 // 当前排名位置
    var nextPos: Int = 0 // 下一年份排名位置
    var diffPos: Int = 0 // nextPos - currPos
}

11. 每个年份下有10个国家,10条数据,Y轴上对应的有10个Y坐标的起点,可以算出10个起点内有9个间隔的,每个间隔高度:val heightDiv = (height - 2 * it.offsety - it.offextBarTopY - it.offextBarBottomY - barWidth) / (it.yCount - 1)
12. 间隔高度乘以位置的差值就是当前年份向下一个年份位置纵向上移动的动画,然后把这个间隔固定高度的变化做成animateFloatAsState动画,和长度变化同样的道理,即可。
13. 基本就搞定了。。。

六、总结

本文重点介绍了:
1. 对之前数据模型配置进行优化整理了一次,本文会详细介绍
2. 这次新增条形图,和动态走势趋势图(可配背景音乐录制成视频
3. 重点解说动态走势趋势图是怎样绘制出来的

希望您看完能对你有所帮助

感谢阅读:

欢迎用你发财的小手: 点点赞、收藏收藏,或者 关注关注

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

已经集合到开源库里面
github地址
gitee地址