附以前連接:
用canvas繪製漫天飛舞的雪花1
用canvas繪製漫天飛舞的雪花2html
本次效果:canvas
效果預覽:https://codepen.io/andy-js/pen/YzPYQvzsegmentfault
廢話不說,直接上代碼
與以前的區別在於,增長了雪花隨機出現和從上到下的效果。
而且此次利用了RAF來作動畫。
下一篇會介紹RAF的一些特色。app
<!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>