今天來說解「雷達掃描」效果demo,來源於QQ羣裏邊有羣友說想要個雷達效果,就嘗試寫了一下。javascript
效果圖:html
demo連接: https://win7killer.github.io/demo_set/html_demo/canvas/can_demo/radar.html
java
********************************************************************git
這個東西,背景圓,座標、圓圈都很簡單實現,arc結合moveTo、lineTo就能夠解決,背景色也不是問題,一句帶過。github
那麼,有挑戰的地方,就是這個掃描的東西canvas
特色: 函數
一、旋轉oop
二、漸變ui
開始實現:spa
一、誤入歧途
首先考慮了過渡色,實現過渡色以後,只須要旋轉canvas,恩,完美~(頭腦簡單的例子,後邊發現這思路行不通)
step1. *過渡色*
過渡色只有「線性過渡」、「輻射過渡(環形過渡)」,而這個效果須要的是一種相似於「扇形側面過渡」(木有這種過分,我瞎叫的)。環形過渡並不知足需求,只能考慮線性過渡。
考慮到canvas路徑的填充(fillStyle)可使用過渡色對象,先實現第一幀的過渡,開搞。
代碼以下:
1 var grd = ctx.createLinearGradient(175,100,can.width,150); 2 3 grd.addColorStop(0,"rgba(0,255,0,0)"); 4 grd.addColorStop(1,"rgba(0,255,0,1)");
而後繪製一個扇形,去填充
1 ctx.fillStyle = grd; 2 ctx.beginPath(); 3 ctx.moveTo(150,150); 4 ctx.arc(150, 150, 150, -90/180*Math.PI, 0/180*Math.PI); 5 ctx.fill();
加上背景色
1 ctx.fillStyle = 'rgba(0,0,0,1)'; 2 ctx.strokeStyle = 'rgba(0,255,0,1)'; 3 4 ctx.arc(150,150,150,0,2*Math.PI); 5 ctx.fill();
效果圖以下:
還算有那麼點樣子哦~,接下來就是讓它動起來
step2. *旋轉*
旋轉思路:旋轉點在canvas的中心點,圍繞中心點旋轉,而後不停的繪製掃描區的扇形。
用了以前的旋轉函數
1 function drawRotate(deg, fn) { 2 ctx.save(); 3 ctx.translate(can.width/2, can.height/2); 4 ctx.rotate(deg); 5 fn && fn(ctx); 6 ctx.restore(); 7 }
可是!!!!真的轉起來的時候,問題來了。
扇形的旋轉完美,沒問題,說明這個旋轉函數也沒問題。
問題出在過渡色身上。。。
過渡色建立的時候,走向是固定的,在渲染到扇形後,依舊是同樣的走向(扇形每次都要重繪),致使出現錯誤的結果。
因爲原來的錯誤代碼不全了,因此就沒圖給你們看了。你們能夠本身試一下。
有考慮到在旋轉的過程當中去改變過渡色走向,可是涉及到比較繁瑣的計算,仍是放棄了(比較懶,若是真的去算位置,應該是能夠達到效果的)。
因而放棄,去吃午餐了,大腦確定是去能量了。
二、迷途折返
午餐事後,繼續思考,換思路。
通過考慮,想起之前作「字幕雨」(相似黑客帝國)的思路來。
附: 字幕雨連接:https://win7killer.github.io/demo_set/html_demo/canvas/text_rain.html
思路以下:
總體思路變化,先處理旋轉,再處理過渡。
step1. 旋轉
以小角度(1°-5°)繪製純色的扇形,沒錯,就是純色的,不要過渡色,而後旋轉,以保證掃描區前邊亮色。這樣,旋轉一週,會r讓整個雷達高亮。
注意,這裏的旋轉再也不是旋轉canvas,而是不斷改變繪製扇形的角度。
1 function drawRadar(iDeg) { 2 ctx.fillStyle = 'rgba(0,200,0,.7)'; 3 ctx.beginPath(); 4 ctx.moveTo(150, 150); 5 ctx.arc(150, 150, 150, (-2 * CFG.perDeg + iDeg) / 180 * Math.PI, (0 + iDeg) / 180 * Math.PI); 6 ctx.closePath(); 7 ctx.fill(); 8 }
step2. *扇形*
而後,處理過渡。仔細考慮, 這個並非「過渡色」效果,真的不是,而是「漸進消隱」效果,就是出現後高亮,慢慢消失的效果。
此類「漸進消隱」效果的作法,很簡單,用rgba半透明色(飽和度1的時候與背景色相同)填充整個canvas,一層一層覆蓋上去,就會獲得慢慢消失的效果。
loop如下代碼:
1 function cover() { 2 ctx.save(); 3 ctx.fillStyle = 'rgba(0,0,0,0.02)'; 4 ctx.arc(150, 150, 150, 0, 2 * Math.PI); 5 ctx.fill(); 6 ctx.restore(); 7 }
在整個loop中先去覆蓋以前的,而後去重繪座標、圓環等,重繪該改變角度的扇形,就達到了效果,完美。
最終總體代碼以下:
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>radar</title> <style> canvas { margin: 20px auto; display: block; } </style> </head> <body> <canvas id="can" width=300 height=300></canvas> <script type="text/javascript"> var CFG = { perDeg: 1, }; var can = document.getElementById('can'); var ctx = can.getContext('2d'); var deg = 0; ctx.strokeStyle = 'rgba(0,255,0,1)'; function init() { ctx.fillStyle = 'rgba(0,50,0,1)'; ctx.arc(150, 150, 150, 0, 2 * Math.PI); ctx.fill(); var raf = window.requestAnimationFrame(loop); } function loop() { deg = (deg + CFG.perDeg); cover(); drawPosLine(); drawRadar(deg); raf = window.requestAnimationFrame(loop); } function cover() { ctx.save(); ctx.fillStyle = 'rgba(0,0,0,0.02)'; ctx.arc(150, 150, 150, 0, 2 * Math.PI); ctx.fill(); ctx.restore(); } function drawPosLine() { ctx.beginPath(); ctx.moveTo(150, 0); ctx.lineTo(150, 300); ctx.closePath(); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, 150); ctx.lineTo(300, 150); ctx.closePath(); ctx.stroke(); ctx.moveTo(150, 150); ctx.beginPath(); ctx.arc(150, 150, 100, 0 * Math.PI, 2 * Math.PI); ctx.closePath(); ctx.stroke(); ctx.moveTo(150, 150); ctx.beginPath(); ctx.arc(150, 150, 50, 0 * Math.PI, 2 * Math.PI); ctx.closePath(); ctx.stroke(); } function drawRadar(iDeg) { ctx.fillStyle = 'rgba(0,200,0,.7)'; ctx.beginPath(); ctx.moveTo(150, 150); ctx.arc(150, 150, 150, (-2 * CFG.perDeg + iDeg) / 180 * Math.PI, (0 + iDeg) / 180 * Math.PI); ctx.closePath(); ctx.fill(); } init(); </script> </body> </html>
至此,完成效果,符合預期,完美~
****************************************************
感謝各位收看,下期再見~~~