這是一個仿支付寶芝麻信用分的一個canvas,其實就是一個動畫儀表盤。javascript
首先, 上原圖:css
這個是在下支付寶上的截圖,分低各位見笑了。而後看下我用canvas實現的效果圖:html
<canvas id="canvas" width="400" height="700" data-score='724'></canvas> <!-- 設置data-score,分數區間[400, 900] -->
唉,總感受不像。這個是GIF圖,可能在網頁上打開的效果會好一點(固然可能就是這樣)。你們能夠點擊底部預覽codepen上的演示。有兩個不完美的地方,一個是實際上芝麻信用錶盤上的的刻度是不均勻的,我這爲了簡單的實現就採起相同的刻度;二是錶盤上運動的點是有模糊的效果,還沒解決。唉,下次再說吧。java
接下來仍是來講說怎麼實現的吧。第一步,國際慣例,建立畫布:web
var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), cWidth = canvas.width, cHeight = canvas.height;
而後繪製錶盤,雖然說不是處女座,但也要儘量作到跟原圖上的同樣,那就是這個環形開口的角度是多少呢?請上ps來測一下:canvas
嗯,136°,這個角度確實刁鑽,爲了方便接下來的計算,那就約等於140°。那麼一個分數段的弧度就是:函數
var deg1 = Math.PI * 11 / 45
先把中間半透明的刻度層畫好:動畫
ctx.save(); //中間刻度層 ctx.beginPath(); ctx.strokeStyle = 'rgba(255, 255, 255, .2)'; ctx.lineWidth = 10; ctx.arc(0, 0, 135, 0, 11 * deg0, false); ctx.stroke(); ctx.restore();
接着,畫6條刻度線,用for循環來實現:this
ctx.save(); // 刻度線 for (var i = 0; i < 6; i++) { ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(255, 255, 255, .3)'; ctx.moveTo(140, 0); ctx.lineTo(130, 0); ctx.stroke(); ctx.rotate(deg1); } ctx.restore();
同理,再把大刻度細分爲5個小刻度:spa
ctx.save(); // 細分刻度線 for (i = 0; i < 25; i++) { if (i % 5 !== 0){ ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(255, 255, 255, .1)'; ctx.moveTo(140, 0); ctx.lineTo(133, 0); ctx.stroke(); } ctx.rotate(deg1 / 5); } ctx.restore();
刻度到這裏就ok了,還須要給刻度標上文字和每一個分數段的信用級別,具體的參見代碼,由於跟刻度實現的原理差很少,就不囉嗦了。如今最關鍵就是實現錶盤上那個運動的點(不知道怎麼稱呼,下文就叫它動點),咱們能夠這樣想,它是個半徑很小的圓,只不過是畫在最外層環形軌道上圓,而圓在canvas
上的實現方法是:
ctx.arc(x, y, radius, sAngle, eAngle, false);
咱們只要控制x, y就能讓它動起來,實現咱們想要的效果。so,建立一個動點對象:
function Dot() { this.x = 0; this.y = 0; this.draw = function (ctx) { ctx.save(); ctx.beginPath(); ctx.fillStyle = 'rgba(255, 255, 255, .7)'; ctx.arc(this.x, this.y, 3, 0, Math.PI * 2, false); ctx.fill(); ctx.restore(); }; } var dot = new Dot(), dotSpeed = 0.03, //控制動點的速度 angle = 0, //這個很關鍵,用來獲得動點的座標x, y credit = 400; //信用最低分數
如何獲得dot的座標x, y呢?那就要用到傳說中三角函數了。
經過上圖咱們能夠獲得
x = r * cos(angle), y = r * sin(angle)
在JavaScript中,dot的中心座標就變成了:
dot.x = radius * Math.cos(angle); //radius爲最外層軌道的半徑值 dot.y = radius * Math.sin(angle);
接下來咱們只要獲得這個angle。這個經過弧度與分數的比例關係就能夠獲得:
var aim = (score - 400) * deg1 / 100; if (angle < aim) { angle += dotSpeed; } dot.draw(ctx);
而後讓中間的信用分數也能隨動點的轉動而變化,建立一個text()
,爲了使數字變化能和動點保持一致,要根據動點的速率來計算數字變化:
function text(process) { ctx.save(); ctx.rotate(10 * deg0); ctx.fillStyle = '#000'; ctx.font = '80px Microsoft yahei'; ctx.textAlign = 'center'; ctx.textBaseLine = 'top'; ctx.fillText(process, 0 ,10); ctx.restore(); } var textSpeed = Math.round(dotSpeed * 100 / deg1), if (credit < score - textSpeed) { credit += textSpeed; } else if (credit >= score - textSpeed && credit < score) { credit += 1; // 這裏確保信用分數最後停下來是咱們輸入的分數 } text(credit);
最後這一切都逃不過讓window.requestAnimationFrame()來控制繪製動畫和用ctx.clearRect(0, 0, cWidth, cHeight)來清除畫布。
寫的很差,你們將就着看,我相信你們理解代碼的能力必定強於理解我這些我本身都不知道說什麼的文字。
好了,以上。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
|