【Canvas与艺术】雷达显示屏

【说明】

圆形的雷达显示屏由两种雷达探测的结果叠加而成。

整圆表示相控阵雷达,此种雷达探测角度广,侦测距离远,但不精确,得知目标的大致高度位置信息后便交由三坐标雷达做精确探测;

扇面表示三坐标雷达的侦测范围,该种雷达能精确测定目标的方位高度速度,但作用面窄;

实战中常把两种雷达配合起来用,如下图所示。

【图示】

 

【代码】

复制代码
复制代码
<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>雷达显示屏</title>
     </head>

     <body onload="draw()">
        <canvas id="myCanvus" width="512px" height="512px" style="border:0px dashed black;">
            出现文字表示您的浏览器不支持HTML5
        </canvas>
     </body>
</html>
<script type="text/javascript">
<!--
/*****************************************************************
* 将全体代码(从<!DOCTYPE到script>)拷贝下来,粘贴到文本编辑器中,
* 另存为.html文件,再用chrome浏览器打开,就能看到实现效果。
******************************************************************/

// 常量边长
const SideLength=512;

// 绘图上下文
var context;

// 雷达对象
var radar;

function draw(){
    var canvas=document.getElementById('myCanvus');    
    canvas.width=SideLength;
    canvas.height=SideLength;    

    context=canvas.getContext('2d');    
    context.translate(SideLength/2,SideLength/2);
    
    radar=new Radar(SideLength/2);    
    radar.init();

    animate();
};

function animate(){    
    context.clearRect(-SideLength/2,-SideLength/2,SideLength,SideLength);// 清屏
    
    radar.paintBg(context);
    radar.paintScale(context);
    radar.paintPointers(context);

    if(true){
        window.requestAnimationFrame(animate);
    }
}

// 雷达类
function Radar(radius){
    this.radius=radius;
    this.img;
    this.angle=0;

    // 横飞飞机的坐标
    this.x1=-198;
    this.y1=100;

    // 纵飞飞机的坐标
    this.x2=100;
    this.y2=-198;

    // 斜飞飞机的坐标
    this.x3=-150;
    this.y3=-150;
    
    this.init=function(){
        this.img=new Image();
        this.img.src="67.copper.png";
    }

    // 画背景
    this.paintBg=function(ctx){
        // 画雷达最外缘的金属护板
        ctx.strokeStyle="white";
        ctx.beginPath();
        ctx.arc(0,0,this.radius,0,2*Math.PI,true);
        ctx.closePath();
        ctx.stroke();
        
        ctx.clip();// 用以上的圆去切割下面的图片

        ctx.drawImage(this.img,0,0,400,400,-this.radius,-this.radius,2*this.radius,2*this.radius);

        // 画六颗螺丝
        ctx.fillStyle="yellow";
        var hourNumber = ["✪","❂","✪","❂","✪","❂"];
        ctx.font = "18px Arial";//字体也有乘比例 字符串拼接
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";

        hourNumber.forEach(function (text, i) {
            var rad = 2 * Math.PI / 6 * i;
            var x = Math.cos(rad) * 239;
            var y = Math.sin(rad) * 239;

            // 螺丝外缘
            ctx.strokeStyle="black";
            ctx.lineWidth=3;
            ctx.beginPath();
            ctx.arc(x,y,5,0,2*Math.PI,true);
            ctx.closePath();
            ctx.stroke();            
            
            // 螺丝内文
            ctx.fillText(text, x, y);
        });

        // 画深绿色屏幕
        ctx.fillStyle="#006000";
        ctx.beginPath();
        ctx.arc(0,0,224,0,2*Math.PI,true);
        ctx.closePath();
        ctx.fill();

        // 画屏幕与护板之间的橡胶条
        ctx.strokeStyle="black";
        ctx.lineWidth=5;
        ctx.beginPath();
        ctx.arc(0,0,222,0,2*Math.PI,true);
        ctx.closePath();
        ctx.stroke();
        
    };

    //  画刻度
    this.paintScale=function(ctx){
        // 画横轴
        ctx.strokeStyle="#79FF79";
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(-219,0);
        ctx.lineTo(219,0);
        ctx.closePath();
        ctx.stroke();

        // 画纵轴
        ctx.strokeStyle="#79FF79";
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(0,-219);
        ctx.lineTo(0,219);
        ctx.closePath();
        ctx.stroke();

        // 画500公里圆
        ctx.strokeStyle="#79FF79";
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.arc(0,0,109.5,0,2*Math.PI,true);
        ctx.closePath();
        ctx.stroke();

        // 标两个500公里
        ctx.fillStyle="white";
        ctx.font = "8px Arial";
        ctx.textAlign = "left";
        ctx.textBaseline = "bottom";
        ctx.fillText("500km", 109.5, 0);

        ctx.fillStyle="white";
        ctx.font = "8px Arial";
        ctx.textAlign = "right";
        ctx.textBaseline = "bottom";
        ctx.fillText("500km", -109.5, 0);

        // 标两个1000公里
        ctx.fillStyle="white";
        ctx.font = "8px Arial";
        ctx.textAlign = "right";
        ctx.textBaseline = "bottom";
        ctx.fillText("1000km", 219, 0);

        ctx.fillStyle="white";
        ctx.font = "8px Arial";
        ctx.textAlign = "left";
        ctx.textBaseline = "bottom";
        ctx.fillText("1000km", -219, 0);
    };


    // 画指针
    this.paintPointers=function(ctx){
        this.angle+=Math.PI/720;
        let x=Math.cos(this.angle)*219;
        let y=Math.sin(this.angle)*219;

        // 扫描棒
        ctx.strokeStyle="#93FF93";
        ctx.lineWidth=1;
        ctx.beginPath();
        ctx.moveTo(0,0);
        ctx.lineTo(x,y);
        ctx.closePath();
        ctx.stroke();

        // 扫描扇形
        ctx.fillStyle = 'rgba(0,200,0,0.3)';
        ctx.beginPath();
        ctx.moveTo(0, 0);
        ctx.arc(0, 0, 219, this.angle, this.angle-2*Math.PI/360*45,true);
        ctx.closePath();
        ctx.fill();

        // 横飞飞机
        let anglePlane1=Math.atan2(this.y1, this.x1);// 算横飞飞机角度
        if(anglePlane1>this.angle-2*Math.PI/360*45 && anglePlane1<this.angle){
            ctx.fillStyle="#F0FFF0";
        }else{
            ctx.fillStyle="#53FF53";
        }
        
        ctx.font = "10px Arial";
        ctx.textAlign = "left";
        ctx.textBaseline = "bottom";
        ctx.fillText("✈", this.x1, this.y1);

        this.x1+=0.1;
        if(this.x1>198){
            this.x1=-198;
        }

        // 纵飞飞机
        let anglePlane2=Math.atan2(this.y2, this.x2);// 算纵飞飞机角度
        if(anglePlane2>this.angle-2*Math.PI/360*45 && anglePlane2<this.angle){
            ctx.fillStyle="#F0FFF0";
        }else{
            ctx.fillStyle="#53FF53";
        }
        
        ctx.font = "10px Arial";
        ctx.textAlign = "left";
        ctx.textBaseline = "bottom";
        ctx.save();
        ctx.translate(this.x2, this.y2);
        ctx.rotate(Math.PI/2);
        ctx.fillText("✈", 0, 0);
        ctx.restore();

        this.y2+=0.2;
        if(this.y2>192){
            this.y2=-198;
        }

        // 斜飞飞机
        let anglePlane3=Math.atan2(this.y3, this.x3);// 算斜飞飞机角度
        if(anglePlane3>this.angle-2*Math.PI/360*45 && anglePlane3<this.angle){
            ctx.fillStyle="#F0FFF0";
        }else{
            ctx.fillStyle="#53FF53";
        }
        
        ctx.font = "10px Arial";
        ctx.textAlign = "left";
        ctx.textBaseline = "bottom";
        ctx.save();
        ctx.translate(this.x3, this.y3);
        ctx.rotate(Math.PI/4);
        ctx.fillText("✈", 0, 0);
        ctx.restore();

        this.x3+=0.4;
        this.y3+=0.4;
        if(this.y3>150){
            this.x3=-150;
            this.y3=-150;
        }

        // 旋转棒角度变换
        if(this.angle>2*Math.PI){
            this.angle=0;
        }
    };
}

//  常规函数:角度得到弧度
function getRad(degree){
    return degree/180*Math.PI;
}

/*----------------------------------
最是人间留不住 朱颜辞镜花辞树
......
一生如牛不得闲 如闲已与山共眠
----------------------------------*/
//-->
</script>
复制代码
复制代码

【背景图】

这张背景图是用做雷达护板的,下载下来改名为67.copper.png,与代码配合使用。

END

posted @   逆火狂飙  阅读(199)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示