鴻蒙開源第三方組件—MPAndroidChart_ohos圖表繪制組件
前言
本組件是基于安卓平臺的圖表繪制組件MPAndroidChart( https://github.com/PhilJay/MPAndroidChart),實現(xiàn)了其核心功能的鴻蒙化遷移和重構(gòu)。目前代碼已經(jīng)開源到(https://gitee.com/isrc_ohos/mpandroid-chart_ohos),歡迎各位下載使用并提出寶貴意見!
背景
安卓版本的MPAndroidChart在GitHub上有超過3.3萬個Star和8.3k個Fork,應該說是目前使用最廣,體驗最佳的開源圖表庫。它具繪制折線圖、餅圖、雷達圖等圖表的能力,用戶只需要自己寫一個數(shù)據(jù)接口,即可實現(xiàn)各種精美數(shù)據(jù)曲線的繪制,在一定程度上滿足了大部分業(yè)務的需求。
本組件是MPAndroidChart的鴻蒙化版本,名為MPAndroidChart_ohos,實現(xiàn)了其核心功能。
組件效果展示
目前MPAndroidChart_ohos具有折線圖和直方圖兩種圖表繪制能力。下面將分別展示其折線圖和直方圖的繪制效果。
1、折線圖
圖1展示了一個由隨機數(shù)據(jù)生成的折線圖。MPAndroidChart_ohos繼承了原版MPAndroidChart的優(yōu)秀特性,提供了多種多樣的用戶自定義接口,例如:
(1) X、Y軸自定義。使用者可以自定義X、Y軸的位置,例如在這個sample里就繪制了左Y軸和上X軸。
(2)輔助線自定義。使用者可以選擇是否顯示輔助線(或格點線),也可以自由設定輔助線的位置。
(3)圖表美化。使用者可以設置圖表曲線的各種屬性(顏色、粗細等),還可以對曲線包裹區(qū)域進行填充。
圖1 折線圖繪制效果
2、直方圖
圖2是基于假設場景“2020年1月1日 ~ 15日的小賣部收益情況”繪制的圖表?;谶@個背景,使用MPAndroidChart_ohos制作了一張直方圖。
圖2 直方圖繪制效果
Sample解析
圖3 Sample工程結(jié)構(gòu)
圖1和圖2主要依靠調(diào)用Library中的能力繪制,在Sample中的實現(xiàn)主要由圖3中紅框所示的兩個文件來完成。
如果用戶想要繪制圖表,只需要完成以下幾個步驟即可:
(1)選擇圖表種類。
(2)設置屬性。
(3)導入數(shù)據(jù)。
1、選擇圖表種類
MPAndroidChart_ohos提供了折線圖和直方圖的繪制能力,使用者只需要根據(jù)自身需求選擇需要使用的能力即可。
- LineChart chart = new LineChart(context); //折線圖的初始化
- BarChart chart = new BarChart(context); // 直方圖的初始化
- 1.
2、設置屬性
MPAndroidChart_ohos提供了圖表樣式自定義的能力,使用者可以通過調(diào)用Library暴露的接口來給圖表添加、修改、刪除各項屬性。例如使用者想要自定義軸線,可以通過實例化XAxis 類的對象,然后通過對象的各種方法實現(xiàn)修改X軸的顏色,設置最大值、最小值等:
- XAxis xAxis = chart.getXAxis(); // 實例化
- xAxis.setAxisMaximum(20f); //屬性設置
- xAxis.setAxisMinimum(0f);
- xAxis.setAxisLineColor(Color.BLACK.getValue());
- 1.
除了軸線設置以外還可以在圖表中加入各種輔助線,例如想要在x = 2處添加一條輔助線,可以通過實例化LimitLine 類的對象,然后通過對象的各種方法實現(xiàn)修改輔助線的寬度、標簽位置、文本大小等:
- LimitLine llXAxis = new LimitLine(2f, "輔助線:x=2"); // 實例化
- llXAxis.setLineWidth(4f); //屬性設置
- llXAxis.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM);
- llXAxis.setTextSize(10f);
- llXAxis.setTypeface(Font.DEFAULT);
3、導入數(shù)據(jù)
在MPAndroidChart_ohos中,不同類型的圖表有著不同的數(shù)據(jù)類,例如折線圖的數(shù)據(jù)類為LineData,直方圖的數(shù)據(jù)類為BarData,為什么不能僅僅通過一個簡單int[]或者float[]作為數(shù)據(jù)類呢?這是因為在MPAndroidChart_ohos中數(shù)據(jù)類的作用不僅僅是承載數(shù)據(jù),同時還需要承載一些圖表相關的屬性,例如曲線顏色、曲線粗細、數(shù)據(jù)點顏色、大小等,這樣做的意圖在后續(xù)Library分析時會講到。
以折線圖為例,導入數(shù)據(jù)的過程如下:
(1)創(chuàng)建LineDataSet類:
- LineDataSet set1 = new LineDataSet(values, label);
其中values是使用者想要繪制的一類數(shù)據(jù),一般是float[],label是這類數(shù)據(jù)的標簽。
(2)將一類或者幾類數(shù)據(jù)放置到一個ArrayList中
- ArrayList<ILineDataSet> dataSets = new ArrayList<>(); dataSets.add(set1);
(3)將ArrayList做成LineData數(shù)據(jù)類,并傳遞給chart
- LineData data = new LineData(dataSets);
- chart.setData(data);
Library解析
1、工程結(jié)構(gòu)對比
圖 4 MPAndroidChart_ohos(上)與MPAndroidChart (下)的工程結(jié)構(gòu)對比
從圖4中的兩張圖的對比可以看出,MPAndroidChart_ohos是按照MPAndroidChart工程的結(jié)構(gòu)開發(fā)的,實現(xiàn)了其主要功能。相較于MPAndroidChart,雖然MPAndroidChart_ohos缺少exception、highlight、jobs這幾個文件夾,但并不影響其主要功能的使用。
2、多設備適配
為了增加多設備適配性,MPAndroidChart內(nèi)部以dp(density independent pixels)為單位來計算圖表中各個部件的相對位置,在繪制圖表時,統(tǒng)一將dp數(shù)據(jù)轉(zhuǎn)化為pixel數(shù)據(jù),在這個過程中就需要系統(tǒng)提供一些顯示信息。在安卓中,這些信息由DisplayMetrics來提供,如下代碼可以通過上下文獲取到DisplayMetrics:
- Resources res = context.getResources();
- mMetrics = res.getDisplayMetrics();
接下來通過DisplayMetrics可以獲取到屏幕的DPI,dp * DPI即為屏幕的pixel:
- public static float convertDpToPixel(float dp) {
- return dp * mMetrics.density;
- }
在鴻蒙系統(tǒng)中,顯示信息通過DisplayAttribute類來獲取,以下代碼可以獲取到DisplayAttribute:
- Display display = DisplayManager.getInstance().getDefaultDisplay(this.getContext()).get();
- DisplayAttribute displayAttribute = display. getAttributes()
可以看出與安卓還是有些許不同的。得到DisplayAttribute后即可得到屏幕DPI,需要注意的是代表DPI的接口與安卓不同:
- public static float convertDpToPixel(float dp) {
- return dp * mMetrics.densityPixels;
- }
3、軸線繪制
軸線是一張圖的基準,在MPAndroidChart中,軸線甚至作為了圖表種類的分類基準!看似MPAndroidChart提供了十余種圖表繪制的能力,其實這十余種圖表是依托于兩種軸線制作的,這兩種軸線分別是平面直角坐標系和極坐標系。
在直角坐標系下,MPAndroidChart實現(xiàn)了折線圖、散點圖、直方圖、氣泡圖、蠟燭圖等。
在極坐標系下,MPAndroidChart實現(xiàn)了餅圖、雷達圖。
在MPAndroidChart_ohos中,和軸線相關的類主要分布在components文件夾和renderer文件夾中:
圖5 軸線類與軸線繪制類
其中AxisBase類主要定義了軸應具備的屬性,例如顏色、粗細、位置、刻度、標簽、最值等。XAxis和YAxis繼承自AxisBase,并分別定義了X、Y軸所應具備的屬性,例如:X軸的位置屬性應是“Top”、“BOTTOM”、“TOP_INSIDE”、“BOTTOM_INSIDE”或“BOTH_SIDED”中的一種;而Y軸與X軸不同,其位置屬性應為“LEFT”或“RIGHT”。
AxisRenderer類是繪制軸線的基類,其定義了繪制軸線所必備的屬性和方法,例如用于繪制軸線、標簽、輔助線、格點的幾種畫筆(Paint)和對應的方法接口。XAxisRenderer和YAxisRenderer繼承自AxisRenderer,實現(xiàn)了其中用于繪制的接口,真正實現(xiàn)了軸線的繪制。其他的諸如XAxisRenderHorizontalBarChart類從名字上看也容易得知是在一些特殊圖表上繪制軸線用的。
4、數(shù)據(jù)繪制
圖6 折線圖相關的數(shù)據(jù)類
在Sample解析中提到對于不同類型的圖表,需要不同的數(shù)據(jù)類去承載數(shù)據(jù)和屬性。數(shù)據(jù)類的繼承關系是MPAndroidChart中比較復雜的一部分內(nèi)容,舉一個例子來說,我們繪制折線圖所需的LineData類,它繼承自:
- public class LineData extends BarLineScatterCandleBubbleData<ILineDataSet> {
類名有點長,不過沒關系,繼續(xù)向下尋找:
- public abstract class BarLineScatterCandleBubbleData<T extends IBarLineScatterCandleBubbleDataSet<? extends Entry>> extends ChartData<T> {
- 1.
ChartData類應該就是根了:
- public abstract class ChartData<T extends IDataSet<? extends Entry>> {
看似三級繼承關系并不算多,但是值得注意的是期間需要實現(xiàn)的接口和泛型參數(shù)是非常多的,這些接口和泛型往往還都能繼續(xù)向下嵌套好多層,這著實給移植工作帶來了一些困難。下面來看看這些數(shù)據(jù)類是做什么的。
ChartData類是數(shù)據(jù)類的基類,在其中首先定義了數(shù)據(jù)的上界和下界分別是浮點數(shù)所能代表的最大和最小值,同時該類提供了一些數(shù)據(jù)處理方法,例如如果發(fā)現(xiàn)任何數(shù)超過了上、下界,都將這些數(shù)強制賦值為上、下界,避免溢出帶來的數(shù)據(jù)錯誤。同時這個類還提供了諸如查詢數(shù)據(jù)點個數(shù)、查詢數(shù)據(jù)X、Y值、查詢標簽、查詢最大、最小值等數(shù)據(jù)查詢方法。
BarLineScatterCandleBubbleData和LineData分別是對ChartData的一次和二次封裝,本身并沒有添加任何方法,只是通過實現(xiàn)接口與各種泛型參數(shù)對存入其中的數(shù)據(jù)格式加以限制。
圖 7 折線圖的繪制類
那么數(shù)據(jù)點和曲線是如何繪制到圖表中的?DataRenderer是數(shù)據(jù)繪制的基類,其中寫出了繪制數(shù)據(jù)、曲線、標簽等的抽象方法。繼續(xù)以折線圖為例,這些抽象方法將在DataRendereràBarLineScatterCandleBubbleRendereràLineScatterCandleRadarRendereràLineRadarRendereràLineChartRenderer這個繼承路徑中被逐步實現(xiàn),最終LineChartRenderer實現(xiàn)了繪制折線圖的全部能力。
項目貢獻人
吳圣垚 鄭森文 朱偉 陳美汝 張馨心