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