canvas動畫特效 之 星空

大力美少女發表於2019-04-11

解析

用了requstAniFrame,瀏覽器每隔1000/60ms進行重繪 ,然後使用迭代完成無限運動 ,每個粒子是用建構函式來建立。
總體的配置使用靜態類來做,值得一提的是滑鼠移入時附近粒子變大,我是在靜態類裡面存放了一個存放初始半徑的陣列,從裡面取值並賦值給存放粒子的陣列,為的是不讓粒子一直變大,形成555555的節奏

動畫原理:

  1. 全域性配置(粒子個數,存放粒子陣列,存放粒子半徑陣列,粒子之間的最小距離,粒子距離滑鼠的最小距離)
  2. 單個粒子配置,使用建構函式(顏色,半徑,速度),把粒子存入全域性配置中的存放粒子的陣列,對應半徑存入全域性配置中的存放粒子半徑的陣列
  3. 利用requstAniFrame進行重繪,每次先清除畫布,然後迴圈出全域性變數存放的值,進行移動等操作

效果

canvas動畫特效 之 星空

程式碼

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
    *{
        padding: 0;
        margin: 0;
    }
    html,body{
        width: 100%;
        height: 100%;
        overflow: hidden;
        /*background-color: #020215;*/
    }

    </style>
</head>
<body>
    <canvas id="canvas"></canvas>
</body>
</html>
<script type="text/javascript">
    //相容requestAnimFrame
    window.requestAnimFrame = ( function() {
        return window.requestAnimationFrame ||
                    window.webkitRequestAnimationFrame ||
                    window.mozRequestAnimationFrame ||
                    function( callback ) {
                        window.setTimeout( callback, 1000 / 60 );
                    };
    })();
    //背景繪製函式
     function drawBg(cvs)
      {
        cvs.beginPath();
        cvs.fillStyle="#020215";
        cvs.fillRect(0,0,wW,wH);
        cvs.save();
      }
    //隨機數0-255(rgb)
    function ran255(){
        return Math.round(Math.random()*255);
    }
    //隨機顏色建構函式
    function Color(){
        this.r=ran255();
        this.g=ran255();
        this.b=ran255();
        this.rgb="rgba("+this.r+","+this.g+","+this.b+",1)";
    }
    window.onload=function()
    {
      var can=document.getElementById("canvas");
      can.width=wW=window.innerWidth;
      can.height=wH=window.innerHeight;      
      var cvs=can.getContext("2d");
      //繪製背景     
      drawBg(cvs);
      //建立粒子配置(總體),靜態類
      var Dots=
      {
        n:300,
        minDis:50,
        d_mouse:100,
        array:[],
        radiusArr:[]
      }
      //每個粒子的配置
      function Dot()
      {
        this.color = new Color();//建立隨機顏色
        //圓心座標
        this.x = Math.round(Math.random()*wW);
        this.y = Math.round(Math.random()*wH);
        //速度(不同方向)
        this.vx = (Math.random()-0.5)*3;
        this.vy = (Math.random()-0.5)*3;
        //隨機半徑
        this.radius = Math.round(Math.random()*5);
      }
      //初始化
      Dot.prototype.draw = function() {
        cvs.beginPath();
        cvs.fillStyle = this.color.rgb;
        cvs.arc(this.x,this.y,this.radius,0,360,false);
        cvs.fill();
      };
      //建立粒子並放入陣列
      for(var i=0;i<Dots.n;i++)
      {
        var dotObj = new Dot();
        Dots.array.push(dotObj);
        Dots.radiusArr.push(dotObj.radius);
      }

      //畫出粒子
      function drawDots()
      {
        drawBg(cvs);
        for(var i=0;i<Dots.n;i++)
          {
            Dots.array[i].draw();
          }
      }
      drawDots();
      //移動粒子
      function moveDots(){          
        for(var i=0;i<Dots.n;i++)
          {
            var dot = Dots.array[i];
            //反彈判斷
            if(dot.x <0 || dot.x>wW)
                {
                    dot.vx=-dot.vx;
                }
            if(dot.y <0 || dot.y>wH)
                {
                    dot.vy=-dot.vy;
                }
            dot.x += dot.vx;
            dot.y += dot.vy;
          }
      }
     //混合顏色

     //連線
     function connect()
     {
         function mixColor(dot1,dot2)
         {
            var color1=dot1.color;
            var color2=dot2.color;
            var r1=dot1.radius;
            var r2=dot2.radius;
            var r=Math.floor((color1.r*r1+color2.r*r2)/(r1+r2));
            var g=Math.floor((color1.g*r1+color2.g*r2)/(r1+r2));
            var b=Math.floor((color1.b*r1+color2.b*r2)/(r1+r2));
            return "rgba("+r+","+g+","+b+",1)"
         }
        for(var i=0;i<Dots.n;i++)
        {           
            for(var j=0;j<Dots.n;j++)
            {
                var dot1 = Dots.array[i];
                var dot2 = Dots.array[j];
                var color=mixColor(dot1,dot2);
                if(Math.abs(dot1.x-dot2.x)<Dots.minDis && Math.abs(dot1.y-dot2.y)<Dots.minDis)
                {
                    cvs.lineWidth=0.2;
                    cvs.beginPath();
                    cvs.strokeStyle=color;
                    cvs.moveTo(dot1.x,dot1.y);
                    cvs.lineTo(dot2.x,dot2.y);
                    cvs.stroke();
                }
            }
        }
     }
     can.onmousemove=function(ev)
     {
        var ev=window.event || ev;
        var pX=ev.pageX;
        var pY=ev.pageY;        
        for(var i=0;i<Dots.n;i++)
        {  

            if(Math.abs(Dots.array[i].x-pX)<Dots.d_mouse && Math.abs(Dots.array[i].y-pY)<Dots.d_mouse)
            {
                var r=Dots.radiusArr[i]*5;
                Dots.array[i].radius=r;
            }
            else{
                Dots.array[i].radius=Dots.radiusArr[i];
            }
         }

     }
     //無限運動
     function infinateDot()
     {
        cvs.clearRect(0,0,wW,wH);
        moveDots();
        drawDots();
        connect();
        requestAnimationFrame(infinateDot)
     }
     infinateDot();
    }
</script>
複製程式碼

相關文章