jinxiutong 2020-05-03
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 中设置的大小是表示了图片本身的大小
<!DOCTYPE html> <html lang="en"> <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>火把</title> <style> html,body{ margin:0; width:100%; height:100%; /* font-size: 0; */ } canvas{ background: #000; vertical-align: bottom; /* width:100%; height:100%; */ } </style> </head> <body> <canvas id="torch" width="600px" height="600px"></canvas> <script> let ele=document.getElementById(‘torch‘); ele.width=document.documentElement.clientWidth; ele.height=document.documentElement.clientHeight; let ctx=ele.getContext(‘2d‘); //初始化,存放火焰的数组 let arrTorch=[]; // 鼠标的当前位置 let mouse={}; for(let i=0;i<8;i++){ arrTorch.push(new torch()); } console.log(arrTorch); function random(min,max){ return min+Math.random()*(max-min); } // 鼠标事件 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; } // 用requestAnimationFrame代替setInterval // 适配不同的浏览器缺少某个方法的一段算法 这段代码的作用就是解决一些浏览器没有requestAnimationFrame这个方法 //像这样的一段算法,或者说代码,是有名词来称呼它的叫做 垫片(polyfill) window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback){ setInterval(callback,16.7) }; // 构造火焰 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 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(); </script> </body> </html>