李煥麗
(中國煤炭科工集團太原研究院山西天地煤機裝備有限公司 山西省太原市 030006)
隨著智能手機的普及,手機APP的使用量急速上升,人們更多的是希望通過手機便捷、快速的瀏覽信息,因此手機APP開發(fā)已經(jīng)成為當(dāng)前一項很熱門的技術(shù)。市面上有這樣一類APP,需要將幾組上萬條數(shù)據(jù)以曲線的形式顯示在手機屏幕上,并且具有左右滑動功能、多點觸控縮放功能,如股票走勢分析軟件、溫度趨勢分析軟件。而此類功能并沒有成熟的API供開發(fā)者使用[1,2,3,6],如果開發(fā)者想要將曲線顯示功能靈活的嵌入到自己的軟件中,需要做大量的編程工作,這就給開發(fā)者帶來了一定的困難。
本文針對以上問題,本文參考張軍[4]、張偉[5]介紹的在液晶屏或計算機屏幕上顯示溫度數(shù)據(jù)曲線的方法后,以2組3萬多條溫度數(shù)據(jù)為例,基于Android手機,以Graphics類為基礎(chǔ),設(shè)計和開發(fā)了一個繪制動態(tài)曲線圖的API,方便開發(fā)者靈活調(diào)用并嵌入到程序中,該接口函數(shù)實現(xiàn)了4大功能:繪制大量數(shù)據(jù)曲線圖、兩點觸控縮放曲線、單點觸控左右滑動曲線、多組數(shù)據(jù)的曲線顯示。本文依次介紹這4個功能的設(shè)計與實現(xiàn)過程。
Android系統(tǒng)為開發(fā)者提供了Graphics類來繪制曲線圖,Graphics類包含在System.Drawing名稱空間下,此類封裝了繪圖接口,可以繪制曲線、圓弧、線條、矩形和文本等。表1列出了Graphics類中常用的drawLine方法和drawRect方法的參數(shù)及功能描述,這兩個方法分別用于繪制線段和矩形框。
本文使用的實驗數(shù)據(jù)為32000條溫度數(shù)據(jù),而目前主流Android智能手機屏幕的分辨率為1080×2340,假設(shè)顯示溫度數(shù)據(jù)曲線圖的控件的像素為:100×1020(橫向像素點×縱向像素點)。數(shù)據(jù)曲線圖效果圖如1所示,圖中標(biāo)有“A”的紅色虛線是指溫度報警上限警示線,標(biāo)有“B”的紅色虛線是指溫度報警下限警示線。
在手機屏幕上繪制曲線圖的基本思想是:首先依次將溫度數(shù)據(jù)(記錄時間,記錄溫度)換算成手機屏幕上的像素點(橫坐標(biāo),縱坐標(biāo)),然后使用drawLine方法依次將相鄰像素點連接,這樣就形成了溫度曲線,直觀形象地描繪出了溫度數(shù)據(jù)的變化趨勢。
表1:drawLine、drawRect方法及功能描述
表2:data≤displaydata時的縮放等級定義
表3:data>displaydata時的縮放等級定義
表4:事件發(fā)生位置的獲取方法
表5:MotionEvent對象事件列表
顯然手機一屏并不能描出所有溫度數(shù)據(jù)的像素點,因此在確保正確反映溫度數(shù)據(jù)變化趨勢的前提下,使用數(shù)據(jù)壓縮算法,將數(shù)據(jù)壓縮到一定數(shù)據(jù)量,并放在一屏顯示,方便用戶觀察。數(shù)據(jù)壓縮算法過程如下。
使用Java自帶的View.getWidth()方法、View.getHeight()方法分別獲取顯示溫度曲線的控件的橫向分辨率和縱向分辨率,使用公式(1)來定義曲線圖初始狀態(tài)下一屏曲線圖最多可顯示的數(shù)據(jù)量,即壓縮后的數(shù)據(jù)量,記為displaydata。公式中的wn根據(jù)實際情況自定義。
圖1:曲線圖在手機上的示意圖
圖2:數(shù)據(jù)壓縮流程圖
數(shù)據(jù)壓縮過程流程如圖2所示,首先將所有數(shù)據(jù)(共data個)分為m組,每組n個數(shù)據(jù)(m、n的計算過程如公式(2)所示),挑選出每組內(nèi)的最大值和最小值并保證二者相對位置不發(fā)生變化,挑選出的數(shù)據(jù)即為壓縮后的數(shù)據(jù)。挑選最值的流程如圖3所示。
通過以上步驟挑選出來的數(shù)據(jù)記為data_init,構(gòu)成初始狀態(tài)下曲線圖上的溫度數(shù)據(jù),將data_init的數(shù)據(jù)轉(zhuǎn)換成手機屏幕的像素點,依次使用表1中的drawLine(x1,y1,x2,y2,paint)方法連接相鄰像素點,直至將所有點用折線連接完畢,即完成了數(shù)據(jù)曲線的繪制。
曲線圖中的警示線具有重要作用,它能快速幫助用戶判斷數(shù)據(jù)是否有超出范圍。
圖1中標(biāo)有“A”、“B”的紅色虛線分別表示溫度報警上限警示線和溫度報警下限警示線。將圖1中顯示曲線圖的控件截取出來,如圖4所示,圖中標(biāo)注了控件的坐標(biāo)軸(是指標(biāo)有“控件的x軸”、“控件的y軸”的坐標(biāo)軸,該坐標(biāo)軸是Android開發(fā)中系統(tǒng)默認(rèn)的控件坐標(biāo)軸,是供開發(fā)人員繪制圖形使用的,坐標(biāo)軸的原點為控件的左上角)和曲線圖坐標(biāo)系的坐標(biāo)軸(是指標(biāo)有“坐標(biāo)系的x軸”、“坐標(biāo)系的y軸”的坐標(biāo)軸,該坐標(biāo)軸是開發(fā)人員繪制出來的呈現(xiàn)給用戶的曲線圖的坐標(biāo)軸,原點為控件的左下角)。繪制溫度報警警示線需要事先換算出圖4中四個點的坐標(biāo),分別調(diào)用drawLine(x1,y1,x2,y2,paint)方法使用虛線畫筆連接兩個端點即可。
圖3:挑選最值流程圖
當(dāng)溫度數(shù)據(jù)數(shù)量遠(yuǎn)大于屏幕分辨率時,曲線圖僅能提供給用戶整體趨勢,用戶更多的是希望通過觸摸屏幕來放大、縮小曲線圖,方便的查看某一局部的數(shù)據(jù)。
圖5顯示了兩點觸控常見的三種形式,圖中point1、point2是用戶初次觸摸的兩點,point1'、point2'分別是point1、point2移動后的觸摸點。
第2.1節(jié)計算出手機一屏最多可顯示的數(shù)據(jù)量為displaydata,現(xiàn)有溫度數(shù)據(jù)data條。若data≤displaydata,初始狀態(tài)下一屏可以顯示全部記錄數(shù)據(jù),定義這種情況下的縮放等級為5級,各級的定義如表2所示。若data>displaydata,初始狀態(tài)下一屏不能顯示全部記錄數(shù)據(jù),因此需要使用第2.1節(jié)中提到的數(shù)據(jù)壓縮算法將數(shù)據(jù)進行壓縮,壓縮完畢后同樣將縮放等級定義為五級,各級的定義如表3所示。
Android系統(tǒng)提供了觸摸機制,當(dāng)用戶使用手指或者電容筆對手機屏幕進行觸控操作時會創(chuàng)建一個MotionEvent對象,該對象包含關(guān)于發(fā)生觸控的位置、動作、時間等詳細(xì)信息,并將其傳遞到系統(tǒng)的View.onTouchEvent()方法中,在該方法中對MotionEvent對象進行分析,確定用戶的操作類型,并執(zhí)行相應(yīng)的操作。獲取MotionEvent對象事件發(fā)生位置的方法見表4,MotionEvent對象的主要事件類型及功能描述見表5。
圖4:曲線圖顯示控件
圖5:三種常見的觸控情況
獲取用戶觸摸的兩個點坐標(biāo)的代碼如下:
float px1 = MotionEvent.getX(0); //獲取第一個觸摸點的橫坐標(biāo)
float py1 = MotionEvent.getY(0); //獲取第一個觸摸點的縱坐標(biāo)
float px2 = MotionEvent.getX(1); //獲取第二個觸摸點的橫坐標(biāo)
float py2 = MotionEvent.getY(1); //獲取第二個觸摸點的縱坐標(biāo)
將兩個觸摸點移動前后的坐標(biāo)分別記為point1(px1,py1)、point2(px2,py2)和point1'(px1',py1')、point2'(px2',py2')。
定義圖5中point1、point2兩點的中心點center(center_x,center_y)為縮放焦點,該點的橫、縱坐標(biāo)計算過程如公式(3)所示。
判斷縮放焦點處是否有記錄數(shù)據(jù),若有,則該數(shù)據(jù)為焦點數(shù)據(jù);若無,需要尋找距離中心點坐標(biāo)最近的記錄數(shù)據(jù),將該數(shù)據(jù)作為焦點數(shù)據(jù)。確定焦點數(shù)據(jù)的流程圖如圖6所示。
分別計算point1、point2兩點和point1’、point2’兩點之間的距離,計算過程如公式(4)所示。若length'>length,說明用戶是要進行放大曲線的操作;反之,若length' 再分別計算出point1、point2兩點的移動距離,計算過程如公式(5)所示。取二者的最大值記為l,根據(jù)表8找到其對應(yīng)的縮放等級進行縮放即可。 表6:移動距離與操作的定義表 表7:兩組溫度數(shù)據(jù)表 由步驟(5)計算出縮放倍數(shù)后根據(jù)表5確定數(shù)據(jù)壓縮的組數(shù)和每組的數(shù)據(jù)量,最后使用drawLine方法將其繪制成曲線圖。 常見的單點觸控情況如圖7所示,圖中point'是point移動后的觸控點,兩點的坐標(biāo)分別為(downXOfFirst,downYOfFirst)、(downXOfSec、downYOfSec)。通 過 計 算downXOfSec與downXOfFirst的差值來判斷用戶的操作,差值與操作對應(yīng)表如表6所示。 假設(shè)兩組溫度數(shù)據(jù)如表7所示,從表中可以看出這兩組溫度數(shù)據(jù)的記錄時間有重疊的部分(如表中加有下劃線的記錄時間),因此需要將這兩組數(shù)據(jù)的記錄時間進行排序和去重操作,然后再將其作為x坐標(biāo)軸的刻度來進行顯示。 使用改進的敗者樹算法排序,使用敗者樹算法進行所條溫度曲線顯示的步驟如下: 首先,在排序之前將所有記錄數(shù)據(jù)的時間合并到一個List HashSet散列法去重的核心代碼如下: HashSet h =new HashSet(x_values); x_values.clear(); x_values.addAll(h); 本文設(shè)計的方法實現(xiàn)了在手機屏幕上動態(tài)繪制大量數(shù)據(jù)曲線圖的功能,并且支持觸控縮放和滑動功能。以接口的方式提供給軟件開發(fā)者,方便調(diào)用,從而將曲線圖靈活地嵌入到程序中,具有重要的參考價值。 圖6:確定中心點數(shù)據(jù)流程圖 圖7:常見的單點觸控情況4 單點觸控移動曲線及移動算法
5 多組數(shù)據(jù)的曲線顯示
6 結(jié)束語