声明:文中的MPChart代指MPAndroidChart.
本系列之前的文章介绍的MPChart中BarChart相关的一些制作,接下来咱们看看LineChart相关的制作。这儿以实践的运动相关的图表数据做业务支撑来解说。MPChart图表支撑多指触控办法,这儿一切的图表自定义都关掉了这个属性,这样就减少Transformer,以及制作过程中的更多的变动,相当于一个静态的图。一般图表在放大的过程中,坐标轴也会随之展示更小的刻度,杂乱度就变高了,具体的显现的刻度就或许呈现小数之类的等状况。
这儿咱们关掉触摸放大后,相当于一个静态的图。这时候,产品以及规划或许需求咱们的X轴坐标、Y轴坐标等刻度尽或许地为整数,这样看起来比较美观。静态的状况下,由于无法移动,即便能够移动,初次展示也期望图表的数据能够比较居中,这就涉及到YAxis的自定义怎么影响操控 Chart的相关展示逻辑的内容,本章节首先从这下手,解说运动数据图表的制作。
- TimeAxis
这儿自定义X轴TimeAxis,实践意义是一次运动耗费的时间,继承自XAxis。假设一次运动1个小时06分钟,规划期望展示4个刻度(0, 20 , 40, 60 分钟), 这时需求咱们自己去操控,假设不加操控的话,Default状况下无法准确的完成规划的需求。
XAxis、YAxis有两个属性,Maximum, Minmum. 这样设定每个interval 就能够核算出要显现的刻度列表, labelList, 加入到XAxis中的 mEntries, 最终在XAxisRender会拿到mEntries 最终制作 X坐标。
这儿不在规划一个算法类核算每个时间段的刻度显现了,运动的时间范围有限,直接枚举, 在 TimeXAxis里的getlabelCount() 完成。
if (max > 6000 * TimeDateUtil.TIME_MIN_INT){
interval = 2000 * TimeDateUtil.TIME_MIN_INT;
} else if (max > 4800 * TimeDateUtil.TIME_MIN_INT) {// 80个小时
interval = 1920 * TimeDateUtil.TIME_MIN_INT;
} else if (max > 2400 * TimeDateUtil.TIME_MIN_INT) {// 40个小时
interval = 960 * TimeDateUtil.TIME_MIN_INT;
} else if (max > 1200 * TimeDateUtil.TIME_MIN_INT) {
interval = 480 * TimeDateUtil.TIME_MIN_INT;
}
。。。。。
else if (max > 20 * TimeDateUtil.TIME_MIN_INT) {
interval = 5 * TimeDateUtil.TIME_MIN_INT;
} else if (max > 15 * TimeDateUtil.TIME_MIN_INT) {
interval = 4 * TimeDateUtil.TIME_MIN_INT;//4分钟刻度
} else if (max > 5 * TimeDateUtil.TIME_MIN_INT) {//
interval = 2 * TimeDateUtil.TIME_MIN_INT;//2分钟刻度。
} else {
interval = TimeDateUtil.TIME_MIN_INT;
}
float currentEntry = min;
List<Float> entryList = new ArrayList<>();
do {
entryList.add(currentEntry);
currentEntry += interval;
} while (currentEntry <= max);
labelCount = entryList.size();
mEntryCount = labelCount;
if (mEntries.length < labelCount) {
mEntries = new float[labelCount];
}
for (int i = 0; i < labelCount; i++) {
mEntries[i] = entryList.get(i);
}
准备好XAxis 中的Entry数据后,依旧是交给Buffer,经过Transformer转化,最终制作出来, 自定义TimeAxisRender, 然后 renderAxisLabels() 办法里drawLabel(), 制作XAxis的坐标轴线:
图1.0 XAxis 坐标线的制作
- SportYAxis
Y轴的制作比较XAxis要杂乱一些,自定义的SportYAxis继承自YAxis, TimeXAxis 只要时间数据对应。SportYAxis依据具体的数据业务能够表示 心率, 高度海拔, 速度, 配速,频率等数据。这些数据中, 心率、步频等取值范围能够比如(0, 250)相似这样的能够直接定下来Y轴的Max, Min 值以及对应的刻度,高度海拔有负数的,速度的Max依据 所给数据来定, 配速比较特殊,需求将Y轴 revert。
为了将图表能够居中,一般YAxis 上的Maximum 会比 数据中的极大值要偏大,确保图表不会呈现的太慢,影响美观。依据不同的Sport数据,将Y轴分为以下几种:
// TYPE_FIX_MIN_ZERO = 0; Y轴从固定的0开端 到 max;步频、起跳高度
// TYPE_FIX_MIN_POSITIVE = 1; 从 entryList的 实在的 min(min不能小于0)开端,到max; 心率、速度、划频、Swolf
// TYPE_FIX_COMMON = 2; 从entryList的最小值min开端到max的最大值,不管最大、最小是否为Positive, 例如海拔;
//TYPE_FIX_RESTRICT_MAX = 3; 约束最大值,比如配速。Y轴 Invert,所以最小值min为大于等于 0 的Positive value; 配速
public static final int TYPE_FIX_MIN_ZERO = 0;
public static final int TYPE_FIX_MIN_POSITIVE = 1;
public static final int TYPE_FIX_COMMON = 2;
public static final int TYPE_FIX_RESTRICT_MAX = 3;
每种类型下核算Y轴的Maximum、Minmum; 然后核算刻度的间距 itemValue, 得到 坐标Label 的List。
以上的几种坐标的完成具体在 SportYAxis 中完成。
将Y轴数据约束下来之后,图表的展示由于Y轴的Maximum、Minmum 约束在比较居中的位置。
关于配速,当运动停下来时,单位距离的耗时或许无限大,假设咱们考虑把这个极值画下来的话,Y轴或许跨度很大导致图表无法看,所以需求约束极大值,截断图形:
//约束最大值
private float getYAxisMax2(List<SportRecordEntry> values, float yAxisMin) {
int size = values.size();
float yAxisMax = Integer.MIN_VALUE;
float yAxisMinTemp = Integer.MAX_VALUE;
float sum = 0;
for (int i = 0; i < size; i++) {
SportRecordEntry entry = values.get(i);
yAxisMax = Math.max(entry.getY(), yAxisMax);
yAxisMinTemp = Math.min(entry.getY(), yAxisMinTemp);
sum += entry.getY();
}
float averageY = sum / (size * 1.0f);
float distanceMin = averageY - yAxisMinTemp;
float distanceMax = yAxisMax - averageY;
int num = (int) (distanceMax / distanceMin);
if (num > 5) {// 配速中 有 配速值很慢的点,坐标时不考虑它们了。
yAxisMax = averageY + 2 * distanceMin; // 约束Y 轴坐标。
}
float distance = yAxisMax - yAxisMin;
if (yAxisMax > 0 && distance <= 2) {
return yAxisMax + 2;
}
return yAxisMax + distance * mLineChartAttr.maxYAxisRatio;
}
- CustomLineChart
处理完XAxis、YAxis的数据及制作后,处理LineChart的主体,这儿包含了折线图、曲线图等表现数据展示的,还有drawFill, 底部的填充;drawMaxMinPop() 极值点的制作等。侧重解说折线图的制作,关于LineChart,Entry比较简单,存有对应的X, Y值,
图1.1CustomLineChart 制作逻辑
考虑先后两个点,PreEntry, CurrentEntry 然后 制作每段折线,最终连成图表。
针对 配速图表Y轴需求倒过来的,
private float getYAsInverted(Entry entry) {
final float phaseY = mAnimator.getPhaseY();
float yValueRange = mYAxis.getAxisMaximum() - mYAxis.getAxisMinimum();
if (mYAxis.isInverted()) {
if (entry.getY() <= mYAxis.getAxisMinimum()) {
return entry.getY() * phas
eY;
} else {
return (yValueRange - entry.getY()) * phaseY;
}
} else {
return entry.getY() * phaseY;
}
}
以下便是配速图表,极大值的约束线取的太大,导致整个图形太偏上了,能够做呼应的修正。 图1.2配速图表线形图
制作底部的Fill, 将一切的点连线,再衔接到底部的X点坐标,最终形成闭环的Path,
图1.3 drawFill
以上大致便是线性图表的制作逻辑,考虑X轴、Y轴的Label的设定,制作,Y轴的极值设定来操控图表图形呈现的位置;配速表的这种Y轴图形的invert, 底部的drawFill().
自此大体的自定义制作解说完了。后续会做些弥补,步频散点图,极值的制作,RTL相关等。 \