效果源碼 git
終於到年末了,再過兩天我也要回家過年了,想一想就激動呢!今天給你們帶來一個基於移動端的canvas價格選擇效果。github
主要功能就是拖動標尺變更價格。並且支付寶和京東金融的裏也有這樣的效果(果真天下設計都是你抄我我抄你啊?)。canvas
效果演示地址函數
整個效果的核心就是用canvas繪製的標尺。一共包括標尺主體,數字,和中間固定不變的標定軸,這幾個部分都用canvas繪製。最上面的大號價格文字,由於其餘地方會須要用它來計算相關的收益。因此,咱們就用個DOM來呈現,這樣比較方便獲取。工具
標尺拖動的距離與價格之間有有一個映射關係,是整個效果最很差處理的部分,在具體處理到相關問題的時候咱們再作分析。如今,咱們先實現基礎的標尺繪製。動畫
咱們先定義一個類叫Rule.js
, 其具體屬性以下。this
如今咱們來了解一下每一個屬性的含義:spa
x, y
: 標尺的座標位置vx
: 標尺的移動速度ax
: 標尺移動加速度color
: 繪製標尺線條的顏色,與文字顏色scaleX, scaleY
: 縮放比markShort, markLong
: 標尺長短線的長度textHeight
: 文字距離標尺主體的高度min, max
: 要展現的最大值和最小值width
: 標尺的像素寬度step
: 步長seg
: 段數pxStep
: 在canvas上的實際步長(單位爲px)minPxStep
: 每一個pxStep分10小段,每小段的實際像素寬度lineBottom
: 底部橫線參數lineRed
: 標定軸參數參數比較多,但真正須要傳入的參數其實並非不少。這裏我講解一下(8)~(15)這幾個參數的思路。設計
min, max : 參數的做用是設置須要顯示的最大金額和最小金額。這兩個參數是外部傳入的,好比設定用戶最小能存100元,最大能存100000萬元。那麼min和max就分別對應100和100000。調試
width : 是整個標尺的實際屏幕長度,好比你只想標尺繪製1000px,那這裏就傳1000就行了。
step : 步長的含義就是每隔多少分一段,好比咱們設定的最大金額爲10000元, 那設置step爲1000就意味着,每隔1000元表示一個小段,這也是canvas上標尺刻度須要繪製的數據。
seg : 段數等於總金額max除以step。
pxStep : 爲真正映射到canvas上的像素步長。
miniPxStep : 每一個pxStep分爲10小段,每小段的像素距離。
lineBottom : 獨立出來不和標尺刻度一塊兒繪製,在繪製標尺的底部橫線時,我是這樣想的。底部橫線的寬度其實就是canvas的寬度,不必從標尺的初始畫到標尺的結尾。並且爲了用戶體驗,刻度的初始位置和結束位置都位於整個canvas的中心。因此,若是合在一塊兒繪製,你須要先繪製一段沒刻度的橫線,而後再繪製刻度,到最後還要繪製一段沒刻度的橫線。這給無疑讓繪製和後續的標尺移動變得至關麻煩。因此我把它抽出來,就是一條貫穿canvas的普通橫線。
lineRed : 標定軸,始終在canvas的中間,也獨立出來不和標尺刻度一塊兒繪製。
屬性都有了,下面添加一個draw方法,把咱們的標尺繪製出來。
a) 繪製標尺刻度部分
這裏有個截圖錯誤,應該是i+=this.miniPxStep
。這應該不難理解,就是每隔miniPxStep
繪製一次線段,線段的類型根據n
這個變量來肯定。
b) 繪製標尺文字部分
文字的繪製不能以真實的屏幕像素爲準,必須映射到金額上,因此,這裏繪製的數字是(n/10)* this.step
。同時,還作了一個特殊的處理,就是初始值是1,不是0。由於,咱們的金額不容許輸入0元。若是你不須要這個,把這裏註釋掉就ok了。
c) 繪製底部橫線
d) 繪製標定軸
這樣整個標尺就完成了,rule.js文件在頂部的github中。如今咱們調用一下這個文件,看看畫出來的效果怎樣。
這裏咱們設置了最大額度爲100000元,最小額度爲500元。整個標尺的長度爲5000px,步長step爲1000元。效果圖以下:
讓標尺偏移個200px, 好比設置: x: ruleX - 200
, 效果以下:
設置步長step爲500,效果以下:
ok,如今靜態標尺就繪製完成,下一步就要完成交互功能,讓標尺可以跟隨鼠標滾動,而且展現當前拖動的金額。
如今咱們開始實現標尺的拖動。標尺的拖動原理很簡單,就是讓標尺的位置跟隨鼠標移動。這裏爲了演示方便我換成了鼠標事件,到移動端換成touch事件便可。
首先引入咱們的工具函數utils.js
文件,而後定義幾個變量。
isMouseDown
用來判斷鼠標是否擡起, oldX
用來記錄上一次拖動的位置,mouse
是使用captureMouse
返回的對象,返回鼠標在canvas上的當前位置信息。
而後,監聽canvas的鼠標事件mousedown, mouseup, mousemove
。並改變rule的位置。
當鼠標按下時,isMouseDown
變爲true, offsetX
在上面忘記寫了,它的做用是記錄鼠標按下的位置與標尺位置之間的偏移量。而後在鼠標移動時標尺的位置rule.x = mouse.x - offsetX
。若是不這樣作,在點擊canvas並拖動標尺的一瞬間,你會發現標尺的初始位置會瞬移到鼠標點擊位置,這樣體驗很很差,咱們須要無論點擊哪,標尺都會在現有的位置跟隨鼠標移動。若是,沒法體會,動手試一試去掉回事什麼效果。
oldX
也很好理解,就是記錄標尺上一次的位置,這裏尚未用到它,後面可能會用到。
如今咱們把標尺的繪製寫進動畫函數中
看看動畫效果如何。
ok,如今咱們已經實現了標尺跟隨鼠標的拖動。下一步,咱們就把拖動的金額顯示出來。
首先,增長一個input
輸入框,而後獲取它。
這裏設置了輸入框的最小值爲標尺的最小額度,這裏能夠先不用管它。咱們主要看onMouseMove
函數
注意money
的計算值,它爲(centerX - rule.x)*rule.ratioScale
。 (centerX - rule.x)
比較好理解,由於,咱們的標尺是從canvas的中心點繪製的。但rule.ratioScale
在最開始的構造函數中並無定義。這裏須要在構造函數中加上,它的含義是每像素表明多少錢,能夠認爲是圖形比例尺。
this.ratioScale = Math.floor(this.max / this.width) //比列尺
那麼天然,移動距離乘以比例尺就得出錢數了。咱們看看效果。
注意到上面的效果中金額顯示出現了負數,因此咱們須要對移動範圍作限制。讓其只能在限定的最大和最小金額之間移動。
對必定範圍的限定主要分爲兩部分。1、標尺範圍的限定。2、金額顯示的限定。這兩部分咱們放在一塊兒作。
1)重設標尺的初始位置
假設咱們設置的最小金額爲500元,那麼初始標定軸的位置應該就是500元的位置。因此初始化標尺的位置後,咱們給它重置爲最小金額的位置。這時候須要把金額換算一下。
rule.x = centerX - rule.min / rule.ratioScale;
就是把金額值得計算倒一下。
2)限定標尺的移動範圍
這裏定義了一個檢測邊界值得函數,當金額小於最小投資金額時,標尺的位置爲初始位置start(注意這個初始位置是已經被重置過的), 而且設置金額爲最小額度。最大位置同理。
而後,在onMouseMove
中調用。
看看效果圖。
標尺的移動除了拖動之外,咱們也但願經過金額輸入框來達到。即輸入金額,標尺便移動到目標金額的位置。
同時咱們也作了邊界限定,當輸入的金額小於或者大於設定值時會,設置標尺的位置和輸入框的顯示爲邊界值,看看效果。
如今拖動的還比較不天然,咱們想要手指離開後標尺還會繼續移動,直到速度慢慢減爲0。爲此,新建兩個變量。
var speed = 0, fl = 0.95; //初始速度, 摩擦係數
新建一個move
函數,在動畫循環中調用。
至此,拖動輸入的核心功能就開發完了。若是你要在項目中使用,另外一個須要注意的事情是canvas在移動端的模糊問題,這個已經有了不少的解決方案,你只須要耐心調試就好。最後仍是祝你們新年快樂,源碼在頭部地址哦。