網站首頁 編程語言 正文
引言
聲明:文中的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相關等。
原文鏈接:https://juejin.cn/post/7138238565850775559
相關推薦
- 2023-10-14 c/c++--__attribute__ 機制
- 2022-04-17 使用docker-compose構建鏡像并構建服務時,想為構建的鏡像統一加上指定版本
- 2022-09-05 基于React?Context實現一個簡單的狀態管理的示例代碼_React
- 2022-09-21 Shell自動化配置SSH免密登錄和取消SSH免密配置腳本_linux shell
- 2021-12-06 Go語言實現一個簡單生產者消費者模型_Golang
- 2021-10-25 C語言編寫漢諾塔游戲_C 語言
- 2022-03-11 UE4 WorldComposition加載Level與位置偏移代碼分析
- 2022-12-14 Android使用Room操作數據庫流程詳解_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支