附之前链接:
用canvas绘制漫天飞舞的雪花1
用canvas绘制漫天飞舞的雪花2
本次效果:
效果预览:https://codepen.io/andy-js/pen/YzPYQvz
废话不说,直接上代码
与之前的区别在于,增加了雪花随机出现和从上到下的效果。
并且这次利用了RAF来做动画。
下一篇会介绍RAF的一些特点。
<!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>andy-js:用canvas绘制漫天飞舞的雪花3</title>
<style>
*{margin:0;padding:0}
html,body{height:100%;}
body{
background: url('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1578308683306&di=4da4218c7fa2ea098ebb0f4f2cb59d95&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1211%2F20%2Fc0%2F15914543_1353393939331.jpg') no-repeat center center;
background-size: 100% 100%;
}
</style>
</head>
<body>
<script>
class Snowflake{
constructor(ctx){
this.ctx=ctx;
};
render({width,x,y,angle}){
this.width=width; //雪花外框大小
this.x=x;
this.y=y;
this.angle=angle;
this.ctx.save();
this.init();
this.bole();
this.ctx.restore();
};
init(){ //初始化
this.lineWidth=parseInt(this.width/60); //主干线的宽度
this.lineHeight=this.width/2*0.8; //主干线的 长度
if(this.lineHeight<1)this.lineHeight=1;
this.heightArr=[ this.lineHeight*0.12,this.lineHeight*0.12,this.lineHeight*.2,this.lineHeight*0.3 ];
this.ctx.lineWidth=this.lineWidth;
this.ctx.strokeStyle='#fff';
this.ctx.fillStyle="#fff";
this.ctx.translate(this.x,this.y);//重新映射画布上的 (0,0) 位置 映射到雪花位置
//旋转 起始度
if(this.angle!=0)this.ctx.rotate( this.angle*Math.PI/180 );
};
bole(){
for(let i=0;i<6;i++){
this.ctx.lineCap="round";//向线条的每个末端添加圆形线帽。
this.ctx.fillStyle="#fff";
this.ctx.beginPath();
this.ctx.moveTo(0,0);
this.ctx.lineTo(0,-this.lineHeight);
this.ctx.stroke();
//画顶端圆
this.ctx.beginPath();
this.ctx.arc(0,-this.lineHeight,this.lineWidth*1.5,0,Math.PI*2,true);
this.ctx.fill();
//画支线
this.branch();
//旋转
this.ctx.rotate(Math.PI/3);
};
};
branch(){ //画分支
let lineHeight=this.lineHeight;
let start=0,
gap=parseInt(lineHeight /4); //每根分支的间距
for(let i=0;i<4;i++){
this.ctx.lineCap="round";//向线条的每个末端添加圆形线帽。
let spot=this.getXY(45,this.heightArr[i]);
this.ctx.beginPath();
this.ctx.moveTo(0,start);
this.ctx.lineTo(spot.x, start+spot.y );
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(0,start);
this.ctx.lineTo(-(spot.x), start+spot.y );
this.ctx.stroke();
start-=gap;
};
};
getXY(angle,radius){ //通过正余弦区取XY坐标
return {
x:Math.sin((180-angle)*Math.PI/180)*radius,
y:Math.cos((180-angle)*Math.PI/180)*radius
}
};
background(w,h){
// this.ctx.fillStyle="#000";
// this.ctx.fillRect(0,0,w,h);
this.ctx.clearRect(0,0,w,h); //清除
};
};
var oC1=document.createElement('canvas');
ctx = oC1.getContext("2d");
var w=document.documentElement.clientWidth,h=document.documentElement.clientHeight
oC1.setAttribute('width',w);
oC1.setAttribute('height',h);
document.body.appendChild(oC1);
var renderSnow=new Snowflake(ctx);
var snows=[];
function rander(a){
//console.log(a); //当前时间间隔
renderSnow.background(w,h);
//之前生产过的雪花
let l=snows.length;
for(let i=0;i<l;i++){
let o=snows[i];
o.y+=4; //往下
o.angle+=15;
if(o.angle>360)o.angle=o.angle%360;
renderSnow.render(o);
if(o.y>h+o.width/2){
snows.splice(i,1);
i--;
l=snows.length;
};
};
//新增的雪花,每次新增1个,随机位置,随机宽度
let snowWidth=rnd(20,50);
let newO={
ctx:ctx,
width:snowWidth,
x:rnd(0,w),
y:-snowWidth,
angle:rnd(0,360)
};
snows.push(newO);
renderSnow.render(newO);
requestAnimationFrame(rander);
};
requestAnimationFrame(rander); //推荐使用 利用原生RAF绘制动画
function rnd(n,m){
return Math.random()*(m-n+1)+n;
};
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。