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>