canvas 实现火焰的简单方式

Posted jeanchjy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了canvas 实现火焰的简单方式相关的知识,希望对你有一定的参考价值。

实现效果如下

技术图片

实验方法:

1. 火焰的构造

 // 构造火焰
        function torch(){ 
            // 构造出来的菱形的对角线一半的长度
            this.width=random(18,30); 
            this.maxWidth=this.width;
            // 火焰位置
            if(mouse.x&&mouse.y){
                this.location={
                    x:mouse.x,
                    y:mouse.y
                }
            }else{
                 // 表示鼠标不在当前范围中则采用固定的位置
                this.location={
                    x:Math.floor(ele.width/2),
                    y:Math.floor(ele.height/2)
                }
              
            }
            // 中心点
            this.rectCenterPoint = {x:this.location.x, y:this.location.y-this.width }; // 矩形中心点
            // this.windy=random(-.1,.1);
            // 运动速度
            this.speed={
                x: random(-.2,.5),
                y: random(1.5,2.5)
            }
            // 火焰存活时间
            this.life=this.width*random(1,2);
            this.remaining_life=this.maxWidth/this.life;
            this.radius = Math.sqrt(Math.pow(this.width,2)+Math.pow(this.width,2));
            this.g=random(20,70);
            
            // 绘制菱形
            this.rect=function(ctx){
                ctx.beginPath(); 
                ctx.shadowBlur=2;
                ctx.shadowColor="rgb(215,148,21)";

                // 画菱形
                // ctx.translate(this.rectCenterPoint.x, this.rectCenterPoint.y);
                // ctx.rotate(45*Math.PI/180);
                // ctx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);

                // // ctx.fillStyle = ‘rgb(255,255,0,.5)‘;
                // ctx.fillStyle=`rgba(${random(245,255)},${this.g},37,${random(.5,1)})`;
                // ctx.fillRect(this.location.x, this.location.y,this.width,this.width);
                // ctx.fill();
                // ctx.rotate(-45*Math.PI/180);
                // ctx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);

                ctx.moveTo(this.location.x,this.location.y);
                ctx.lineTo(this.location.x-this.width,this.location.y-this.width);
                ctx.lineTo(this.location.x,this.location.y-2*this.width);
                ctx.lineTo(this.location.x+this.width,this.location.y-this.width);
                ctx.lineTo(this.location.x,this.location.y); 
                // 渐变颜色                 
                let grd = ctx.createRadialGradient(this.rectCenterPoint.x,this.rectCenterPoint.y,random(1,8),this.rectCenterPoint.x,this.rectCenterPoint.y, this.radius);
                grd.addColorStop(1,`rgba(245,${this.g},37,.8)`);
                grd.addColorStop(0,`rgb(244,${random(37,71)},37)`);
                ctx.fillStyle=grd; 
                ctx.fill();
                ctx.closePath()
            }
        
        }

 function random(min,max){
          return min+Math.random()*(max-min);
        }

 

菱形的构造有两种方法推荐,一种是直接用moveTo+lineTo 直接连接画出(推荐这种),

  一种是通过矩形的旋转与平移,但是矩形的旋转rotate,旋转之后是改变了canvas画布的方向,而不是单纯的矩形的旋转;也因为是改变了画布的方法,所以画布的坐标是根据旋转之后的的位置重新定位的

 技术图片技术图片

上面是平移或旋转之后画布的位置(以坐标轴看出)

2.初始化数据

//初始化,存放火焰的数组
        let arrTorch=[]; 
         // 鼠标的当前位置 
        let mouse={};
        for(let i=0;i<8;i++){
            arrTorch.push(new torch());     
        }

3.鼠标位置获取

// 鼠标事件
        window.onmousemove= function (event){
            let e = event|| window.event;
            let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
            let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
            mouse.x = e.pageX || e.clientX + scrollX;
            mouse.y= e.pageY || e.clientY + scrollY;  
        }
        window.onmouseout = function() {
            mouse.x= null;
            mouse.y= null;
        }

 

4.绘制画布

//实例化
        function draw(){        
           ctx.clearRect(0,0,ele.width,ele.height);
            // ctx.globalCompositeOperation = ‘destination-over‘
            for (var i = 0; i < arrTorch.length; i++) {
                var p = arrTorch[i];   
                p.rect(ctx);              
                p.width-=p.remaining_life;
                // 每次移动 有关颜色的参数的变化
                p.g+=random(50,65);
                // 位置变化
                p.location.y-=p.speed.y;
                p.location.x= p.location.x-p.speed.x;
                // 若菱形长度为0 或者生存时间为0 
                if(p.width<0||p.remaining_life<0){
                    // 当前的菱形重新实例化一次
                    arrTorch[i]=new torch();
                }
            }
           requestAnimationFrame(draw);
        }
       draw(); 

5. 其他

css 样式

<style>
        html,body{
            margin:0;
            width:100%;
            height:100%; 
            /* font-size: 0;  */
        }
        canvas{
            background: #000;
            vertical-align: bottom;
            
            width:100%;
            height:100%;
        }
    </style>

html

<canvas id="torch" width="600px" height="600px"></canvas>

  注:canvas 是一个行内元素,css 设置大小是显示图片在屏幕内像素的大小     在html 中设置的大小是表示了图片本身的大小

完整代码

技术图片
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6     <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7     <title>火把</title>
  8     <style>
  9         html,body{
 10             margin:0;
 11             width:100%;
 12             height:100%; 
 13             /* font-size: 0;  */
 14         }
 15         canvas{
 16             background: #000;
 17             vertical-align: bottom;
 18             
 19             /* width:100%;
 20             height:100%; */
 21         }
 22     </style>
 23 </head>
 24 <body>
 25     <canvas id="torch" width="600px" height="600px"></canvas>
 26     <script>
 27         let ele=document.getElementById(‘torch‘);
 28         ele.width=document.documentElement.clientWidth;    
 29         ele.height=document.documentElement.clientHeight;
 30         let ctx=ele.getContext(‘2d‘);
 31         
 32         //初始化,存放火焰的数组
 33         let arrTorch=[]; 
 34          // 鼠标的当前位置 
 35         let mouse={};
 36         for(let i=0;i<8;i++){
 37             arrTorch.push(new torch());     
 38         }
 39         console.log(arrTorch);
 40        
 41         function random(min,max){
 42           return min+Math.random()*(max-min);
 43         }
 44 
 45         // 鼠标事件
 46         window.onmousemove= function (event){
 47             let e = event|| window.event;
 48             let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
 49             let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
 50             mouse.x = e.pageX || e.clientX + scrollX;
 51             mouse.y= e.pageY || e.clientY + scrollY;  
 52         }
 53         window.onmouseout = function() {
 54             mouse.x= null;
 55             mouse.y= null;
 56         }
 57         // 用requestAnimationFrame代替setInterval
 58         // 适配不同的浏览器缺少某个方法的一段算法 这段代码的作用就是解决一些浏览器没有requestAnimationFrame这个方法
 59         //像这样的一段算法,或者说代码,是有名词来称呼它的叫做 垫片(polyfill)
 60 
 61         window.requestAnimationFrame = window.requestAnimationFrame 
 62                                         || window.mozRequestAnimationFrame 
 63                                         || window.webkitRequestAnimationFrame 
 64                                         || window.msRequestAnimationFrame
 65                                         || function(callback){
 66                                             setInterval(callback,16.7)
 67                                             };
 68 
 69         // 构造火焰
 70         function torch(){ 
 71             // 构造出来的菱形的对角线一半的长度
 72             this.width=random(18,30); 
 73             this.maxWidth=this.width;
 74             // 火焰位置
 75             if(mouse.x&&mouse.y){
 76                 this.location={
 77                     x:mouse.x,
 78                     y:mouse.y
 79                 }
 80             }else{
 81                  // 表示鼠标不在当前范围中则采用固定的位置
 82                 this.location={
 83                     x:Math.floor(ele.width/2),
 84                     y:Math.floor(ele.height/2)
 85                 }
 86               
 87             }
 88             // 中心点
 89             this.rectCenterPoint = {x:this.location.x, y:this.location.y-this.width }; // 矩形中心点
 90             // this.windy=random(-.1,.1);
 91             // 运动速度
 92             this.speed={
 93                 x: random(-.2,.5),
 94                 y: random(1.5,2.5)
 95             }
 96             // 火焰存活时间
 97             this.life=this.width*random(1,2);
 98             this.remaining_life=this.maxWidth/this.life;
 99             this.radius = Math.sqrt(Math.pow(this.width,2)+Math.pow(this.width,2));
100             this.g=random(20,70);
101             
102             // 绘制菱形
103             this.rect=function(ctx){
104                 ctx.beginPath(); 
105                 ctx.shadowBlur=2;
106                 ctx.shadowColor="rgb(215,148,21)";
107 
108                 // 画菱形
109                 // ctx.translate(this.rectCenterPoint.x, this.rectCenterPoint.y);
110                 // ctx.rotate(45*Math.PI/180);
111                 // ctx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);
112 
113                 // // ctx.fillStyle = ‘rgb(255,255,0,.5)‘;
114                 // ctx.fillStyle=`rgba(${random(245,255)},${this.g},37,${random(.5,1)})`;
115                 // ctx.fillRect(this.location.x, this.location.y,this.width,this.width);
116                 // ctx.fill();
117                 // ctx.rotate(-45*Math.PI/180);
118                 // ctx.translate(-this.rectCenterPoint.x, -this.rectCenterPoint.y);
119 
120                 ctx.moveTo(this.location.x,this.location.y);
121                 ctx.lineTo(this.location.x-this.width,this.location.y-this.width);
122                 ctx.lineTo(this.location.x,this.location.y-2*this.width);
123                 ctx.lineTo(this.location.x+this.width,this.location.y-this.width);
124                 ctx.lineTo(this.location.x,this.location.y); 
125                 // 渐变颜色                 
126                 let grd = ctx.createRadialGradient(this.rectCenterPoint.x,this.rectCenterPoint.y,random(1,8),this.rectCenterPoint.x,this.rectCenterPoint.y, this.radius);
127                 grd.addColorStop(1,`rgba(245,${this.g},37,.8)`);
128                 grd.addColorStop(0,`rgb(244,${random(37,71)},37)`);
129                 ctx.fillStyle=grd; 
130                 ctx.fill();
131                 ctx.closePath()
132             }
133         
134         }
135         
136 
137         //实例化
138         function draw(){        
139            ctx.clearRect(0,0,ele.width,ele.height);
140             // ctx.globalCompositeOperation = ‘destination-over‘
141             for (var i = 0; i < arrTorch.length; i++) {
142                 var p = arrTorch[i];   
143                 p.rect(ctx);              
144                 p.width-=p.remaining_life;
145                 // 每次移动 有关颜色的参数的变化
146                 p.g+=random(50,65);
147                 // 位置变化
148                 p.location.y-=p.speed.y;
149                 p.location.x= p.location.x-p.speed.x;
150                 // 若菱形长度为0 或者生存时间为0 
151                 if(p.width<0||p.remaining_life<0){
152                     // 当前的菱形重新实例化一次
153                     arrTorch[i]=new torch();
154                 }
155             }
156            requestAnimationFrame(draw);
157         }
158        draw();  
159       
160     </script>
161 </body>
162 </html>
View Code

 

以上是关于canvas 实现火焰的简单方式的主要内容,如果未能解决你的问题,请参考以下文章

基于深度学习的火焰检测系统(YOLOv5清新界面版,Python代码)

Three.js 火焰

perf + 火焰图分析程序性能

[转]perf + 火焰图分析程序性能

perf + Flame Graph火焰图分析程序性能

使用 CANVAS 实现交互性圆形马赛克效果