Javascriptでcanvasに花火アニメーションを描画する

Javascriptでcanvasに花火アニメーションを描画する


Javascriptでcanvasに花火アニメーションを描画します。Sin、Cosで座標を計算して描画しています。



<canvas class="Hanabi" style="width:100%;max-width:800px;height:200px;"></canvas>

<script>
  TMamHanabi=function(){
    this.can=[];
    this.ctx=[];
    this.width=[];
    this.height=[];
    this.position=[];
    this.basewh=[];
    this.basesp=[];
    this.limit=[];
    this.flag=[];
    this.child=[];
    this.init=function(){
      this.can=document.querySelectorAll(".Hanabi");
      for(let i=0;i<this.can.length;i++){
        this.ctx[i]=this.can[i].getContext("2d");
        //見た目のサイズを取得
        let style = window.getComputedStyle(this.can[i]);
        this.width[i]=parseInt(style.width);
        this.height[i]=parseInt(style.height);
        this.basewh[i]=Math.min(this.width[i],this.height[i]);
        this.basesp[i]=this.height[i]/200;
        //内部のサイズの設定
        this.can[i].setAttribute("width",this.width[i]+"px");
        this.can[i].setAttribute("height",this.height[i]+"px");
        this.position[i]=[];
        this.position[i]["x"]=this.width[i]/2;
        this.position[i]["y"]=this.height[i];
        this.limit[i]=this.height[i]*1/3+Math.random()*this.height[i]/3-this.height[i]/6;
        this.flag[i]=0;
        this.child[i]=[];
        this.reset(i);
        this.ctx[i].fillStyle="#000";
        this.ctx[i].fillRect(0,0,this.width[i],this.height[i]);
      }
    }
    this.reset=function(i){
      this.position[i]["x"]=this.width[i]/3+this.width[i]*Math.random()/3;
      this.position[i]["y"]=this.height[i];
      this.limit[i]=this.height[i]*1/3+Math.random()*this.height[i]/3-this.height[i]/6;
      this.flag[i]=0;
      let ct=0;
      for(let j=0;j<12;j++){
        for(let k=0;k<(j+1)*8;k++){
          let deg=360/((j+1)*8);
          this.child[i][ct]=[];
          this.child[i][ct]["x"]=this.position[i]["x"];
          this.child[i][ct]["y"]=this.limit[i];
          let rd=Math.random();
          this.child[i][ct]["vx"]=Math.cos(deg*k*Math.PI/180)*(j+0.8+rd*Math.random()*0.4)*this.basewh[i]/640/5;
          this.child[i][ct]["vy"]=Math.sin(deg*k*Math.PI/180)*(j+0.8+rd*Math.random()*0.4)*this.basewh[i]/640/5;
          let rr,gg,bb;
          rr=Math.floor(Math.random()*j/2+255-j*2);
          gg=Math.floor(Math.random()*j/4+255-j*8);
          bb=Math.floor(Math.random()*j/16+255-j*16);
          this.child[i][ct]["c"]=''+rr+','+gg+','+bb+'';
          ct++;
        }
      }
    }
    this.draw=function(){
      for(let i=0;i<this.ctx.length;i++){
        this.ctx[i].fillStyle="#000";
        this.ctx[i].fillRect(0,0,this.width[i],this.height[i]);
        if(this.flag[i]==0){
          if(this.position[i]["y"]<this.limit[i]){
            this.flag[i]=1;
          }else{
            this.position[i]["y"]-=this.basesp[i];
          }
          let x=this.position[i]["x"];
          let y=this.position[i]["y"];
          let r=this.basewh[i]/80+Math.random()*this.basewh[i]/80;
          var rgrd = this.ctx[i].createRadialGradient(x, y, r, x, y, 0);
          let rr=Math.floor(Math.random()*5+250);
          let gg=Math.floor(Math.random()*55+200);
          let bb=Math.floor(Math.random()*55+200);
          rgrd.addColorStop(0.0, 'rgba('+rr+','+gg+','+bb+',0.0)');
          rgrd.addColorStop(0.2, 'rgba('+rr+','+gg+','+bb+',0.2)');
          rgrd.addColorStop(1.0, 'rgba('+rr+','+gg+','+bb+',0.8)');
          this.ctx[i].beginPath();
          this.ctx[i].arc(x, y, r, 0, 2 * Math.PI);
          this.ctx[i].fillStyle = rgrd;
          this.ctx[i].fill();
        }else if(this.flag[i]>0){
          if(this.flag[i]>100){this.flag[i]=-50;return;}
          var r;
          for(let j=0;j<this.child[i].length;j++){
            r=(1+Math.random()/2)*this.basewh[i]/128;
            this.child[i][j]["vy"]+=this.basewh[i]/160/200*(1+Math.random()/8);
            this.child[i][j]["x"]+=this.child[i][j]["vx"];
            this.child[i][j]["y"]+=this.child[i][j]["vy"];
            let rgrd = this.ctx[i].createRadialGradient(
              this.child[i][j]["x"], this.child[i][j]["y"], r,
              this.child[i][j]["x"], this.child[i][j]["y"], 0
            );
            let op=(100-this.flag[i])/100;
            rgrd.addColorStop(0.0, 'rgba('+this.child[i][j]["c"]+','+0.0*op+')');
            rgrd.addColorStop(0.6, 'rgba('+this.child[i][j]["c"]+','+0.8*op+')');
            rgrd.addColorStop(1.0, 'rgba('+this.child[i][j]["c"]+','+1.0*op+')');
            this.ctx[i].beginPath();
            this.ctx[i].arc(this.child[i][j]["x"], this.child[i][j]["y"], r, 0, 2 * Math.PI);
            this.ctx[i].fillStyle = rgrd;
            this.ctx[i].fill();
          }
          this.flag[i]++;
        }else{
          this.flag[i]++;
          if(this.flag[i]==0){
            this.reset(i);
          }
        }

      }
    }
    window.addEventListener("DOMContentLoaded",this.init.bind(this));
    setInterval(this.draw.bind(this),20);
  }
  MamHanabi=new TMamHanabi(); 
</script>

Copyright 2021 Mam