canvas動畫特效 之 星空

解析

用了requstAniFrame,瀏覽器每隔1000/60ms進行重繪 ,而後使用迭代完成無限運動 ,每一個粒子是用構造函數來建立。
整體的配置使用靜態類來作,值得一提的是鼠標移入時附近粒子變大,我是在靜態類裏面存放了一個存放初始半徑的數組,從裏面取值並賦值給存放粒子的數組,爲的是不讓粒子一直變大,造成555555的節奏javascript

動畫原理:

  1. 全局配置(粒子個數,存放粒子數組,存放粒子半徑數組,粒子之間的最小距離,粒子距離鼠標的最小距離)
  2. 單個粒子配置,使用構造函數(顏色,半徑,速度),把粒子存入全局配置中的存放粒子的數組,對應半徑存入全局配置中的存放粒子半徑的數組
  3. 利用requstAniFrame進行重繪,每次先清除畫布,而後循環出全局變量存放的值,進行移動等操做

效果

代碼

<!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>
複製代碼
相關文章
相關標籤/搜索