【canvas系列】canvas實現"雷達掃描"效果

今天來說解「雷達掃描」效果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>

  

至此,完成效果,符合預期,完美~

****************************************************

 

感謝各位收看,下期再見~~~

相關文章
相關標籤/搜索