根據項目要求,要實現這樣一個儀表盤的效果:html
拿到圖以後首先作一個拆分,分紅幾個小模塊。從裏往外看,首先須要一個內環的刻度條,這個內環刻度條由若干個點構成,因此個人實現方式爲:先畫一根線,經過循環,旋轉獲得一個圓形的刻度條算法
//innerLineNums 爲刻度數量 ctx.save(); for (var i = 0; i <= $this.innerLineNums; i++) { ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(155,157,183,1)'; ctx.moveTo(82, 0); ctx.lineTo(80, 0); ctx.stroke(); //每一個點的弧度,360°弧度爲2π,即旋轉弧度爲 2π / 75 ctx.rotate(2*Math.PI / $this.innerLineNums); } ctx.restore();
其次再是裏面的長刻度線,以及數字標誌,還有中間的文字sql
// 內環刻度線 ctx.save(); for (var i = 0; i < 6; i++) { ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(155,157,183,1)'; ctx.moveTo(82, 0); ctx.lineTo(78, 0); ctx.stroke(); //每10個點分一個刻度,共5個刻度,旋轉角度爲deg1 * 10 ctx.rotate(deg1 * 10); } ctx.restore(); //內環刻度上面數字 ctx.save(); ctx.rotate(Math.PI / 2); for (i = 0; i < 6; i++) { ctx.fillStyle = 'rgba(165,180,198, .4)'; ctx.font = '10px Microsoft yahei'; ctx.textAlign = 'center'; ctx.fillText(20 * i, 0, -65); ctx.rotate(deg1 * 10); } ctx.restore(); //內環文字 ctx.save(); ctx.rotate(210 * Math.PI / 180); ctx.fillStyle = '#000'; ctx.font = '44px Microsoft yahei'; ctx.textAlign = 'center'; ctx.textBaseLine = 'top'; ctx.fillText(process, 0, 10); var width = ctx.measureText(process).width; ctx.fillStyle = '#000'; ctx.font = '20px Microsoft yahei'; ctx.fillText('分', width / 2 + 10, 10);
好了,此時內環的效果已經有了,能夠看到以下效果:canvas
再來看外環的刻度條,外環刻度條有一個缺口,目測估算一下,算缺口爲1/3,即外環的刻度線須要畫120-360°,咱們這裏分數滿分爲100分,從0開始,爲了方便計算就給他畫50根刻度線,那麼每根刻度線的角度deg1的算法爲:this
//弧長計算公式是一個數學公式,爲L=n(圓心角度數)× π(1)× r(半徑)/180(角度制),L=α(弧度)× r(半徑) (弧度制)。其中n是圓心角度數,r是半徑,L是圓心角弧長。 //整個運動的角度是(360-120)度,轉換成弧度就是12π/9,一共分紅了50個分數段,那麼每個分數段就是12π/450 = 2π / 75 //如需旋轉 5 度,可規定下面的公式:5*Math.PI/180。 deg1() { return (Math.PI * 12) / (9 * this.lineNums) }
從這裏咱們知道了外環2/3個圓的刻度線爲50根,那麼內環整個圓的刻度線innerLineNums = 50 * 3 / 2 = 75根。好了,知道角度以後仍是按照以前的方法,畫一根線,而後循環,在旋轉,跳躍畫出灰色的外環刻度線:spa
// 細份內環刻度線 ctx.save(); for (var i = 0; i <= $this.innerLineNums; i++) { ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(155,157,183,1)'; ctx.moveTo(82, 0); ctx.lineTo(80, 0); ctx.stroke(); //每一個點的弧度,360°弧度爲2π,即旋轉弧度爲 2π / 75 ctx.rotate(2 * Math.PI / $this.innerLineNums); } ctx.restore();
這個時候效果是這樣的:.net
還差外環的漸變線,以及線上面的那個點,那根線是根據分數動態畫的,因此長度須要計算,我打算用一個圓弧來實現,上面說過每一個線之間的旋轉弧度爲deg1,那圓弧的長度就等於score * deg1 / 2,根據公式畫出線以下:rest
//色彩段數與彩色刻度條保持一致,線條無間隔,因此段數 * 2 var gradient = ctx.createLinearGradient(0, 0, $this.colorLineNums * 2, 0); gradient.addColorStop("0", "rgba(252,3,44,.6)"); gradient.addColorStop("0.5", "rgba(134,37,168,.6)"); gradient.addColorStop("1.0", "rgba(54,63,255,.6)"); //外環漸變線 ctx.save(); ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = gradient; ctx.arc(0, 0, radius, 0, angle, false); ctx.stroke(); ctx.restore();
此時效果是這樣的:code
還有圓外環綵線上面的圓點,能夠用一個小圓實現,而後改變他的x,y座標便可實現:htm
ctx.save(); ctx.beginPath(); ctx.fillStyle = 'rgba(255, 255, 255, 1)'; ctx.arc(this.x, this.y, 5, 0, Math.PI * 2, false); ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = "rgba(246, 5, 51, 1)"; ctx.stroke(); ctx.restore(); ctx.save(); ctx.beginPath(); ctx.fillStyle = 'rgba(246, 5, 51, 1)'; ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false); ctx.fill(); ctx.restore();
此時,還差個彩色的線,效果以下,額,這個彩色的線如何實現呢,剛開始也是不知如何下手,通過高人指點後,得出結局方案:把漸變色切割,多少根綵線就分割成多少份,而後感謝 嗑瓜子兒gf-顏色漸變的JS代碼 寫的博客,提供了算法
最終效果出來了:
第一次寫canvas組件,此代碼僅供參考,最後感謝[masqli-canvas仿芝麻信用分儀表盤][3],參考了前面兩位博主的代碼才能實現我項目的需求,所謂前人栽樹,後人乘涼,今天把我寫的也分享給你們,能幫到你們就更好,對我本身也算作個筆記了,在此再次感謝兩位博主