前言
由於公司項目需要,要做港股行情的H5版本,經過分析需求,大致有兩塊難點: 一是行情的推送接收,二是行情K線的生成及相關操作。本文章主要分析行情K線的相關實現,由於我們前端團隊之前是沒有相關的工作經驗的,所以我們第一反應就是去網上搜現成的插件或者相關文檔。經過查找我們發現其實網上這方面的資料不多,相關插件也是比較少,比較符合的相關插件有tradingView以及百度團隊開發的ECharts, 但是兩者插件體積比較大而且在H5移動端的處理並不是特別好。經過討論我們決定自研開發。
線上效果
下面是我們H5線上行情系統的實際操作圖, 也可以掃碼體驗。
關鍵點分析
開發這套行情的K線圖表,關鍵點主要有兩點,其一是K線圖,其二是手勢的處理。K線圖難度不是很大在熟悉Canvas畫圖基礎的情況下注意不同區域划分和層級即可,重點在於數據的一些計算和判斷;手勢的處理就比較麻煩了需要考慮到長按,滑動,放大縮小,慣性滑動,觸底加載,橫屏等場景。下面就這些關鍵點進行逐一分析。
具體實現
一,K線圖基礎
1、K線圖基於Z軸(可以理解成css樣式中的z-index)分成了三層:
第一層畫坐標軸的各種文字和線條包括邊框線,XY軸分割線,X軸時間和日期,Y軸價格和成交量成交額等數據文本;
第二層畫主體數據圖包括分時的走勢線,分時的均線,日K的柱狀圖,MA5,MA10,MA20走勢線,最高價,最低價,成交量或成交額的柱狀圖等K線主體數據圖或文本;
第三層畫長按K線時出現的十字線及十字線的數據文本。
最后將三層相對定位在同一坐標即可。
2、Z軸每一層基於Y軸分成了三部分:
第一部分畫上方走勢圖的線條,圖形,文本;
第二部分畫中間時間或日期文本;
第三部分畫下方成交量或成交額的線條,圖形,文本。
以上canvas的顏色、大小、線條粗細寫成插件配置形式即可。
3、幾個需要注意的圖形畫法
3.1、分時圖的畫法邏輯:從第一個數據點的坐標(x0, y0)畫筆開始(beginPath)移動到(moveTo)下一個點的坐標(x1, y1)依次移動到最后一個點的坐標(xn, yn),到最后一點的坐標后移動到第一部分的最右下方點(width, height)然后再移動到第一部分最左下方點(0, height)最后回到起點(x0, y0)形成閉合填充(fill)漸變色(createLinearGradient)關閉畫筆(closePath)。
3.2、K線柱狀圖:這里首先介紹下柱狀圖(可能有點多余)
轉換成canvas畫圖角度其實就是線條和矩形的結合,線條的畫法比較容易,中心柱狀圖需要注意的地方是如果是空心柱狀圖需要疊加兩層矩形第一層的背景色和你主背景色一致第二層畫邊框矩形邊框顏色畫對應的漲跌顏色(這里是紅漲綠跌)所以邊框顏色設置成紅色。下面是一段偽代碼:
其它可能存在難點的地方更多是涉及到計算,例如最高點最低點坐標位置,第二部分時間文本坐標位置及寬度等,這里就不一一介紹了,有問題可以下方留言。
二,手勢事件處理
1、長按事件:
我們知道js中是沒有這個事件的,但是是有觸摸事件,所以這里利用觸摸事件來模擬長按事件。定義從觸摸開始超過200ms不動即為長按,可以在觸摸事件中使用setTimeout定時器超過200ms即執行長按事件,並且設置長按標識,但是這里需要注意的是在滑動事件中清除這個定時器,如果長按事件已經執行那么清除了也不會有影響,如果還沒執行說明還沒到達長按的條件,利用這個特性就能模擬長按事件了,下面是一段偽代碼:
// 觸摸開始事件 touchStartEvent(e) { this.longTapTimeout = setTimeout(() => { this.longTapFlag = true; this.longTap(touchOne); }, 200); }, // 觸摸移動事件 touchMoveEvent(e) { if (this.longTapTimeout) { clearTimeout(this.longTapTimeout); this.longTapTimeout = null; } if (this.longTapFlag) { // 長按滑動事件(即十字線滑動事件) this.touchMove(); } else { // k線滑動事件 this.swipe(); } }
這個事件是雙指事件,在js中是可以通過event.targetTouches的長度來判斷的。實現放大縮小大體思路是:
step1:計算兩指中間坐標點;
step2:計算兩指間的直線距離;
step3:根據直線距離以及上一次的直線距離計算需要放大或縮小的刻度;
step4:計算刻度不變時中間坐標點對應K線數組的索引index1;
step5:計算刻度變動后中間坐標點對應K線數組的索引index2;
step6:變動前后的索引值相減可以獲得變動的柱狀圖條數,重新渲染圖形即可。
這里有幾個點需要注意:1. 縮小時左邊數據已經到底則需要加載更多數據,2.刻度粗細應該設置上下限在達到上下限的時候避免再次渲染圖形。下面是部分計算代碼:
step6:變動前后的索引值相減可以獲得變動的柱狀圖條數,重新渲染圖形即可。
3、慣性滑動事件:
慣性滑動在移動端是個很好的體驗,什么時候會觸發慣性呢,兩次滑動的間隔時間小於一個設定值既可觸發慣性滑動。慣性需要考慮加速度,靈敏度等因素。這里慣性是用的js中requestAnimationFrame方法,存在兼容性問題可以用setTimeout模擬這里不多做兼容處理的介紹,因為大部分機型是兼容的。具體實現為:在滑動開始時記錄時間,在觸摸結束事件中判斷時間間隔是否小於100ms,如果小於100ms則執行慣性滑動事件,根據滑動最后時間和滑動開始時間計算滑動速度,然后根據設置的靈敏度來計算加速度,執行慣性動畫,然后每執行一次慣性事件減少速度直到速度為0停止慣性事件。以下為部分代碼:
這里也有幾點代碼中沒有寫進去的如需要判斷是否已經觸及邊緣、橫屏的處理等等。
3、觸底回彈事件:
觸底回彈主要是需要判斷是否已經到左右兩側的點,設置到達臨界點后允許滑動的K線條數結束滑動后進行慣性回彈至臨界點,慣性回彈類似慣性滑動的處理。以下為主要邏輯代碼:
這里處理橫屏事件是通過輕擊事件來觸發的,如何判斷是否為輕擊事件呢。在觸摸結束事件中判斷觸摸時間小於100ms且移動距離小於5px即視為輕擊事件來觸發橫屏事件。下面為判斷輕擊事件的代碼:
橫屏的實現這里是利用css3的旋轉屬性對canvas進行90度旋轉,旋轉后需要注意的是滑動的時候X軸與Y軸要和豎屏的時候替換來處理。
三,結言
以上是我們自研行情的K線圖部分的處理,難免有些地方存在不足,也希望讀者能給予意見和指導。由於以上代碼大都為代碼片段,所以會存在變量或方法名沒有定義的情況,望多諒解。我們的行情推送是使用websocket推送結合protobuf數據格式來完成的,如果有需要可以另外介紹。
注:本文和CSDN文章h5行情k線開發為同一作者
*轉載請附出處。