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


今天來講解“雷達掃描”效果demo,來源於QQ群里邊有群友說想要個雷達效果,就嘗試寫了一下。

效果圖

 

demo鏈接: https://win7killer.github.io/demo_set/html_demo/canvas/can_demo/radar.html

 

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

這個東西,背景圓,坐標、圓圈都很簡單實現,arc結合moveTo、lineTo就可以解決,背景色也不是問題,一句帶過。

那么,有挑戰的地方,就是這個掃描的東西

特點: 

1、旋轉

2、漸變

 

開始實現:

1、誤入歧途

首先考慮了過渡色,實現過渡色之后,只需要旋轉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 }

但是!!!!真的轉起來的時候,問題來了。

 

扇形的旋轉完美,沒問題,說明這個旋轉函數也沒問題。

問題出在過渡色身上。。。  

過渡色創建的時候,走向是固定的,在渲染到扇形后,依舊是一樣的走向(扇形每次都要重繪),導致出現錯誤的結果。

 

由於原來的錯誤代碼不全了,所以就沒圖給大家看了。大家可以自己試一下。

有考慮到在旋轉的過程中去改變過渡色走向,但是涉及到比較繁瑣的計算,還是放棄了(比較懶,如果真的去算位置,應該是可以達到效果的)。

 

於是放棄,去吃午飯了,大腦肯定是去能量了。

 

2、迷途折返

午飯過后,繼續思考,換思路。

經過考慮,想起以前做“字幕雨”(類似黑客帝國)的思路來。 

附: 字幕雨鏈接: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>

  

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

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

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM