JavaScript動畫基礎:canvas繪製簡單動畫

来源:https://www.cnblogs.com/cs-whut/archive/2020/07/13/13292760.html
-Advertisement-
Play Games

動畫是將靜止的畫面變為動態的藝術.實現由靜止到動態,主要是靠人眼的視覺殘留效應。視覺殘留也叫視覺暫留現象,物體在快速運動時, 當人眼所看到的影像消失後,人眼仍能繼續保留其影像0.1~0.4秒左右的圖像,這種現象被稱為視覺暫留現象。利用人的這種視覺生理特性可製作出具有高度想象力和表現力的動畫影片。 電 ...


      動畫是將靜止的畫面變為動態的藝術.實現由靜止到動態,主要是靠人眼的視覺殘留效應。視覺殘留也叫視覺暫留現象,物體在快速運動時, 當人眼所看到的影像消失後,人眼仍能繼續保留其影像0.1~0.4秒左右的圖像,這種現象被稱為視覺暫留現象。利用人的這種視覺生理特性可製作出具有高度想象力和表現力的動畫影片。

      電影的拍攝和放映就是視覺殘留效應的具體應用。

      大家可能看過組成電影的實際膠片。從錶面上看,它們像一堆畫面串在一條塑料膠片上。每一個畫面稱為一幀,代表電影中的一個時間片段。這些幀的內容總比前一幀有稍微的變化,這樣,當電影膠片在投影機上放映時就產生了運動的錯覺:每一幀都很短並且很快被另一個幀所代替,這樣就產生了運動。

       通過迴圈繪製各幀的圖像就可以實現動畫的效果。

       在Canvas畫布中製作動畫相對來說很簡單,實際上就是繪製幀(圖形或圖像)、擦除、重繪的過程。也就是說,在Canvas中模擬一個動畫過程就是每隔一定時間繪製圖形並且清除圖形,通過定時迴圈操作實現。

1.定時迴圈操作的三個函數

       對於動畫,需要在一段時間內渲染不同的幀,各幀間隔一定的時間在畫布中依次被繪製。為完成定時迴圈操作幀,可以利用etInterval()、setTimeout()和requestAnimationFrame()這三個函數之一。

       (1)setTimeout()方法。

       setTimeout() 方法是HTML DOM Window對象的一個方法,它用於在指定的毫秒數後調用函數或計算表達式。其調用格式為:

      setTimeout(code,millisec);

       其中,參數code表示要調用的函數或要執行的代碼串,millisec表示在執行代碼前需等待的毫秒數。

例如,setTimeout(“draw()”,1000)表示延時1秒後執行函數draw中的代碼。

編寫如下的HTML文件。

<!DOCTYPE html>

<html>

<head>

<title>setTimeout方法的應用</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   function draw(x,y,len,color)

   {

       ctx.fillStyle = color;

       ctx.fillRect(x,y,len,len);

   }

   setTimeout("draw(10,10,100,'red')",1000);

   setTimeout("draw(110,110,200,'blue')",5000);

</script>

</body>

</html>

       在瀏覽器中打開保存這段HTML代碼的html文件,則等待1秒後,會繪製一個邊長為100的紅色正方形,再等待5秒,繪製一個邊長為200的藍色正方形。

       通過這個例子可以知道:(1)setTimeout()方法可以用於延時;(2)setTimeout()方法只執行code一次。如果要多次調用,則需要讓code 自身再次調用 setTimeout()。

       為產生動畫效果,顯然得讓setTimeout()方法多次執行。修改上面的HTML代碼如下。

<!DOCTYPE html>

<html>

<head>

<title>setTimeout方法的應用</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   var i=0;

   function move()

   {

       ctx.fillStyle = 'red';

       ctx.fillRect(i,i,50,50);

       i++;

       if (i==350)

       {

           i=0;

           ctx.clearRect(0,0,400,400);

       }

       setTimeout("move()",10);

   }

   move();

</script>

</body>

</html>

      在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到一個簡單的箭頭伸出動畫,如圖1所示。

 

圖1  簡單的動畫

      (2)setInterval() 方法。

      setInterval()也是HTML DOM Window對象的一個方法,它可按照指定的周期(以毫秒計)來調用函數或計算表達式。其調用格式為:

      setInterval(code,millisec);

      其中,參數code表示要調用的函數或要執行的代碼串, millisec表示周期性執行或調用 code 之間的時間間隔(以毫秒計)。

      setInterval() 方法會不停地調用函數,直到 clearInterval() 被調用或視窗被關閉。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的參數。

      clearInterval() 方法可取消由 setInterval() 設置的 timeout。其調用形式為:

        clearInterval(id_of_setinterval);

      其中參數id_of_setinterval必須是由 setInterval() 返回的 ID 值。

      若用setInterval() 方法實現圖1所示的動畫,則編寫的HTML文件如下。

<!DOCTYPE html>

<html>

<head>

<title>setInterval()方法的應用</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   var i=0;

   function move()

   {

       ctx.fillStyle = 'red';

       ctx.fillRect(i,i,50,50);

       i++;

       if (i==350)

       {

           i=0;

           ctx.clearRect(0,0,400,400);

       }

   }

   setInterval("move()",10);

</script>

</body>

</html>

       (3)requestAnimationFrame()方法。

      requestAnimationFrame是瀏覽器用於定時迴圈操作的一個介面,類似於setTimeout,主要用途是按幀對網頁進行重繪。

       編寫動畫迴圈的關鍵是要知道延遲時間多長合適。一方面,迴圈間隔必須足夠短,這樣才能保證不同的動畫效果顯得更平滑流暢;另一方面,迴圈間隔還要足夠長,這樣才能保證瀏覽器有能力渲染產生的變化。大多數顯示器的刷新頻率是60Hz,相當於每秒鐘重繪60次。大多數瀏覽器都會對重繪操作加以限制,不超過顯示器的重繪頻率,因為即使超過了這個頻率,用戶體驗也不會有提升。

       因此,最平滑動畫的最佳迴圈間隔是1000ms/60,約等於17ms。以這個迴圈間隔重繪的動畫是平滑的,因為這個速度最接近瀏覽器的最高限速。為了適應17ms的迴圈間隔,多重動畫可能需要加以節制,以便不會完成得太快。

       雖然setTimeout()方法和setInterval()方法均可完成定時迴圈操作,但setTimeout()和setInterval() 都不十分精確。為它們傳入的第二個參數millisec,實際上只是指定了把動畫代碼添加到瀏覽器UI線程隊列以等待執行的時間。如果隊列前面已經加入了其他任務,那動畫代碼就要等前面的任務執行完成後再執行。如果UI線程繁忙,比如忙於處理用戶操作,那麼即使把代碼加入隊列也不會立即執行。

      確定什麼時候繪製下一幀是保證動畫平滑的關鍵。然而,面對不十分精確的 setTimeout()和setInterval(),開發人員至今都沒有辦法確保瀏覽器按時繪製下一幀。因此,採用setTimeout()和setInterval(),即使優化了迴圈間隔,可能仍然只能接近想要的效果。

      引入requestAnimationFrame()方法的目的是為了讓各種網頁動畫效果(DOM動畫、Canvas動畫、SVG動畫、WebGL動畫)能夠有一個統一的刷新機制,從而節省系統資源,提高系統性能,改善視覺效果。代碼中使用requestAnimationFrame()方法,就是告訴瀏覽器希望執行一個動畫,讓瀏覽器在下一個動畫幀安排一次網頁重繪。

      requestAnimationFrame的優勢在於充分利用顯示器的刷新機制,比較節省系統資源。顯示器有固定的刷新頻率(60Hz或75Hz),也就是說,每秒最多只能重繪60次或75次,requestAnimationFrame的基本思想就是與這個刷新頻率保持同步,利用這個刷新頻率進行頁面重繪。

       不過有一點需要註意,requestAnimationFrame是在主線程上完成。這意味著,如果主線程非常繁忙,requestAnimationFrame的動畫效果會大打折扣。

      requestAnimationFrame使用一個回調函數作為參數。這個回調函數會在瀏覽器重繪之前調用。其調用格式為:

       requestID = window.requestAnimationFrame(callback);

       目前,主流瀏覽器(Firefox 23 / IE 10 / Chrome / Safari)都支持這個方法。可以用下麵的方法,檢查瀏覽器是否支持requestAnimationFrame。如果不支持,則自行模擬部署該方法。

        window.requestAnimFrame = (function(){

                  return  window.requestAnimationFrame        ||

                       window.webkitRequestAnimationFrame  ||

                         window.mozRequestAnimationFrame    ||

                            window.oRequestAnimationFrame      ||

                           window.msRequestAnimationFrame     ||

                          function( callback ){

                                window.setTimeout(callback, 1000 / 60);

                        };

          })();

       上面的代碼按照1秒鐘60次(大約每16.7毫秒一次),來模擬requestAnimationFrame。

       與 setTimeout() 和 setInterval() 方法不同,requestAnimationFrame( )不需要調用者指定幀速率,瀏覽器會自行決定最佳的幀效率。也就是說瀏覽器頁面每次要重繪,就會通知requestAnimationFrame。如果瀏覽器繪製間隔是16.7ms,它就按這個間隔繪製;如果瀏覽器繪製間隔是10ms,它就按10ms繪製。這樣就不會存在過度繪製的問題,動畫不會丟幀。

       另外,使用requestAnimationFrame()方法,一旦頁面不處於瀏覽器的當前標簽,就會自動停止刷新。例如,頁面最小化了,頁面是不會進行重繪的,requestAnimationFrame自然也不會觸發(因為沒有通知)。頁面繪製全部停止,資源高效利用,節省了CPU、GPU和電力。

       和setTimeout類似,requestAnimationFrame的回調函數只能被調用一次,並不能被重覆調用(這點和setInterval不同)。因此,使用requestAnimationFrame的時候,同樣需要反覆調用它。

       由於setTimeout可以自定義調用時間, requestAnimationFrame的調用時間則是跟著系統的刷新頻率走的,所以在實現動畫的時候,setTimeout比requestAnimationFrame更加靈活, requestAnimationFrame比setTimeout表現效果更加優秀。

       若用requestAnimationFrame() 方法實現圖1所示的動畫,則編寫的HTML文件如下。

<!DOCTYPE html>

<html>

<head>

<title>requestAnimationFrame方法的應用</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   var i=0;

   function move()

   {

       ctx.fillStyle = 'blue';

       ctx.fillRect(i,i,50,50);

       i++;

       if (i==350)

       {

           i=0;

           ctx.clearRect(0,0,400,400);

       }

       requestAnimationFrame(move);

   }

   move();

</script>

</body>

</html>

2.繪製簡單圖形實現動畫

      圖1的動畫就是從左上角坐標位置(0,0)開始,繪製一個邊長為50的紅色正方形,之後每隔10毫秒後將左上角坐標位置的水平和垂直坐標均增加1,再繪製一個正方形,從而得到一個簡單的箭頭伸出動畫效果。

      通過在畫布中繪製簡單圖形,達到時間間隔後,擦除(有時候也可暫時不擦除)前次繪製的圖形,重新繪製一個位置或大小略有變化的圖形,這樣就可得到動畫效果。

例1  向中心交匯的箭頭。

仿照圖1動畫思想略作變化,編寫如下的HTML代碼。

<!DOCTYPE html>

<html>

<head>

<title>向中心交匯的箭頭</title>

<script type="text/javascript">

   var i=0;

   function draw(id)

   {

      var canvas = document.getElementById(id);

      ctx = canvas.getContext('2d');

      setInterval(painting,10);

   }

   function painting()

   {

      ctx.fillStyle = "green";

      ctx.fillRect(i,i,10,10);

      ctx.fillRect(400-i,400-i,10,10);

      ctx.fillRect(i,400-i,10,10);

      ctx.fillRect(400-i,i,10,10);

      i++;

      if (i==200)

      {

         ctx.clearRect(0,0,400,400);

         i=0;

      }

   }

</script>

</head>

<body onload="draw('myCanvas')">

<canvas id="myCanvas" width="400" height="400"  style="border:3px double #996633;">

</canvas>

</body>

</html>

      在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖2所示的動畫。

 

圖2  向中心交匯的箭頭

      例2  逐層向里繪製的圓。

<!DOCTYPE html>

<html>

<head>

<title>層層向內畫的圓</title>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;"></canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var context = canvas.getContext('2d');

   var flag=1;

   var i=0;

   var r=180;

   function animate() {

      window.requestAnimationFrame(animate);

      draw();

   }

   function draw() {

      var dig=Math.PI/120;

      var x = Math.sin(i*dig)*r+200;

      var y = Math.cos(i*dig)*r+200;

      context.fillStyle = flag ? 'rgb(10,255,255)' : 'rgb(255,100,0)';

      context.beginPath();

      context.arc(x, y, 3, 0, Math.PI*2, true);

      context.closePath();

      context.fill();

      i++;

      if (i>240) {

         i=0;

         r=r-20;

         flag = !flag;

         if (r<=0) {

            context.clearRect(0,0,canvas.width,canvas.height);

            r=180;

         }

      }

   }

   animate();

</script>

</body>

</html>

      在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖3所示的動畫。

 

圖3  層層向內畫的圓

3.通過圖形變換實現動畫效果

      在Canvas中,可以繪製一個基本圖形,然後通過對這個基本圖形使用平移、縮放和旋轉等圖形變換的方法實現動畫效果。

例3  放大縮小的五角星。

<!DOCTYPE html>

<html>

<head>

<title>放大縮小的五角星</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   var x=200;

   var y=200;

   var radius=30;

   var rot=0;

   var dr=5;

   function draw()

   {

       ctx.clearRect(0,0,canvas.width,canvas.height);

       ctx.save();

       ctx.translate(x,y);

       ctx.rotate(rot/180*Math.PI);

       ctx.scale(radius,radius);

       ctx.beginPath();   

       for(var i=0;i<5;i++)   // 繪製標準五角星

       {

             ctx.lineTo(Math.cos((18+i*72)/180*Math.PI),-Math.sin((18+i*72)/180*Math.PI));

             ctx.lineTo(Math.cos((54+i*72)/180*Math.PI)*0.5,-Math.sin((54+i*72)/180*Math.PI)*0.5);

       }

       ctx.closePath();

       ctx.fillStyle="red";

       ctx.fill();

       ctx.restore();

       radius+=dr;    

       if (radius>200 || radius<30)

         dr=-dr;

    }

    setInterval("draw()",60);

</script>

</body> 

</html>

      在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖4所示的動畫。這個動畫效果的變化核心是語句“ctx.scale(radius,radius);”在起作用。

 

圖4  放大縮小的五角星

       若將上面程式段中,radius固定取值120,再修改變化語句

       radius+=dr;    

       if (radius>200 || radius<30)

         dr=-dr;

      為

              rot=(rot+2)%360;

      則五角星會進行旋轉,呈現出如圖5所示的動畫效果。

 

圖5  旋轉的五角星

4.遮罩動畫

       利用Canvas API提供的裁切方法clip(),可以用來實現遮罩動畫。

例4  圖片圓形展開後收縮。

<!DOCTYPE html>

<head>

<title>圓形展開後收縮</title>

</head>

<body>

<canvas id="myCanvas" width="400" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

    var r=10;

    var dr=5;

    var canvas=document.getElementById('myCanvas');

    var ctx=canvas.getContext('2d');

    var image = new Image();

    image.src = 'aaa.jpg';

    image.onload=function(){

        ctx.drawImage(image,0,0);

     }

    setInterval("draw()",100);

    function draw()

    {

           ctx.clearRect(0,0,400,400);

           ctx.save();

          ctx.beginPath();

          ctx.arc(200,200,r,0,Math.PI*2,true);

          ctx.closePath();

          ctx.fillStyle="white";

          ctx.fill();

           ctx.clip();

          ctx.drawImage(image,0,0);

           ctx.restore();

           r=r+dr;

           if (r>280) dr=-5;

           else if (r<=0) dr=5;

    }

</script>

</body>

</html>

       在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖6所示的動畫。

 

圖6  圓形展開後收縮

5.多個同類物體同時運動實現動畫

      有時候設計動畫時,畫布中會有多個同類物體按各自的規律進行運動,這時將各物體抽象為對象數組比較方便處理。

       例3中我們通過圖形變換的方法實現了五角星的放大和旋轉。下麵我們繪製60個五角星在畫布上進行移動的動畫效果。

       例5  60個五角星隨機移動。

       為了描述60個五角星,抽象一個星星對象Star。為該對象定義五角星中心位置坐標(x,y)、五角星外接圓半徑radius、水平方向移動速度speedX、垂直方向移動速度speedY和五角星旋轉角度deg等6個屬性。具體定義如下:

   function Star()

   {

        this.x = randomNum(30,canvas.width-30);

        this.y = randomNum(30,canvas.height-30);

        this.radius=randomNum(8,12);

        this.speedX = randomNum(-5,5);

           this.speedY=randomNum(-5,5);

           this.deg = randomNum(0,180);

    }

       為五角星對象定義兩個方法,一個是update方法,更新五角星的坐標位置(x,y)併進行邊界碰撞檢查;一個方法是draw方法,按屬性設置繪製出五角星。具體定義如下:

    Star.prototype.update = function()

    {

        this.x += this.speedX;

        this.y += this.speedY;

       if (this.x-this.radius<=0)

       {

           this.speedX=-this.speedX;

           this.x=this.radius;

       }

       if (this.x+this.radius>canvas.width)

       {

           this.speedX=-this.speedX;

           this.x=canvas.width-this.radius;

       }

       if (this.y-this.radius<=0)

       {

              this.speedY=-this.speedY;

              this.y=this.radius;

       }

       if (this.y+this.radius>canvas.height)

       {

              this.speedY=-this.speedY;

              this.y=canvas.height-this.radius;

       }

      }

      Star.prototype.draw = function()

      {

           ctx.beginPath();

           for (var i = 0; i < 5; i ++)

           {

                 ctx.lineTo( Math.cos( (18 + i*72 - this.deg)/180 * Math.PI) *this.radius + this.x,

                         -Math.sin( (18 + i*72 - this.deg)/180 * Math.PI) * this.radius + this.y)

                ctx.lineTo( Math.cos( (54 + i*72 - this.deg)/180 * Math.PI) * this.radius/2+ this.x,

                         -Math.sin( (54 + i*72 - this.deg)/180 * Math.PI) * this.radius/2 + this.y)

            }

            ctx.closePath();

            ctx.lineWidth = 3;

            ctx.fillStyle = "#ff0000";

            ctx.strokeStyle = "#ffff00";

            ctx.lineJoin = "round";

            ctx.fill();

            ctx.stroke();

      }

       定義好五角星對象後,定義一個數組stars,保存60個五角星並設置動畫過程。編寫完整的HTML文件如下。

<!DOCTYPE html>

<html>

<head>

<title>滿天都是小星星</title>

</head>

<body>

<canvas id="myCanvas" width="500" height="400" style="border:3px double #996633;">

</canvas>

<script type="text/javascript">

   var canvas = document.getElementById('myCanvas');

   var ctx = canvas.getContext('2d');

   function Star()

   {

        this.x = randomNum(30,canvas.width-30);

        this.y = randomNum(30,canvas.height-30);

        this.radius=randomNum(8,12);

        this.speedX = randomNum(-5,5);

        this.speedY=randomNum(-5,5);

       this.deg = randomNum(0,180);

    }

    Star.prototype.update = function()

    {

          this.x += this.speedX;

          this.y += this.speedY;

           if (this.x-this.radius<=0)

           {

              this.speedX=-this.speedX;

              this.x=this.radius;

           }

           if (this.x+this.radius>canvas.width)

           {

              this.speedX=-this.speedX;

              this.x=canvas.width-this.radius;

           }

           if (this.y-this.radius<=0)

           {

                 this.speedY=-this.speedY;

                 this.y=this.radius;

           }

           if (this.y+this.radius>canvas.height)

          {

                 this.speedY=-this.speedY;

                 this.y=canvas.height-this.radius;

           }

      }

    Star.prototype.draw = function()

    {

           ctx.beginPath();

           for (var i = 0; i < 5; i ++)

           {

                 ctx.lineTo( Math.cos( (18 + i*72 - this.deg)/180 * Math.PI) *this.radius + this.x,

                           -Math.sin( (18 + i*72 - this.deg)/180 * Math.PI) * this.radius + this.y)

                 ctx.lineTo( Math.cos( (54 + i*72 - this.deg)/180 * Math.PI) * this.radius/2+ this.x,

                          -Math.sin( (54 + i*72 - this.deg)/180 * Math.PI) * this.radius/2 + this.y)

            }

            ctx.closePath();

            ctx.lineWidth = 1;

            ctx.fillStyle = "white";

            ctx.strokeStyle = "#ffff00";

            ctx.lineJoin = "round";

            ctx.fill();

            ctx.stroke();

   }

   function randomNum(min,max)

   {

          return Math.floor(Math.random()*(max-min+1)+min);

    }

    var stars = [];

    for (var i = 0; i < 60; i++)

    {

        stars.push(new Star());

        if (stars[i].speedX==0 && stars[i].speedY==0)

            stars[i].speedX=stars[i].speedY=1;

    }

    function move()

    {

           ctx.clearRect(0,0,canvas.width,canvas.height);

        ctx.fillStyle="blue";

           ctx.fillRect(0,0,canvas.width,canvas.height);

        for (var i = 0; i <60; i++)

        {

            stars[i].draw();

            stars[i].update();

         }             

   }

   setInterval("move()",10);

</script>

</body> 

</html>

在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖7所示的動畫。

 

圖7  星星在運動

      例6  下雪了。

      簡單模擬下雪場景,編寫如下的HTML文件。在屏幕中最多有100片雪花,每片雪花繪製一個小圓表示,從畫布頂端開始往下落。由於動畫過程一直在迴圈,因此每當一片雪花落出畫布之外後,隨機為其賦予水平坐標、置垂直坐標置為0、並隨機設置其圓半徑和下落速度,表示這是一片新雪花。這樣,用一個具有100個元素的數組即可保存屏幕中下落雪花的信息。

<!DOCTYPE html>

<html>

<head>

<title>下雪了</title>

</head>

<body>

<canvas id="myCanvas" width="300" height="300" style="border:3px double #996633;">

</canvas>

<script>

    var canvas=document.getElementById('myCanvas');

    var ctx=canvas.getContext('2d');

    var particles = [];

    function loop()

    {

        createParticles();

        downParticles();

        drawParticles();

        window.requestAnimationFrame(loop);

    }

    window.requestAnimationFrame(loop);

    function createParticles()

    {

           if(particles.length <100)

           {

              particles.push({

                    x: Math.random()*canvas.width,

                    y: 0,

                    speed: 2+Math.random()*3, 

                    radius: 3+Math.random()*4, 

              });

           }

    }

    function downParticles()

    {

       for(var i in particles)

       {

          var part = particles[i];

          part.y += part.speed;

          if(part.y > canvas.height) 

          {

               part.x=Math.random()*canvas.width;

               part.y=0;  

               part.speed=2+Math.random()*3; 

               part.radius=3+Math.random()*4; 

          }

       }

    }

    function drawParticles()

    {

       ctx.fillStyle = "black";

       ctx.fillRect(0,0,canvas.width,canvas.height);

       for(var i in particles)

       {

          var part = particles[i];

          ctx.beginPath();

          ctx.arc(part.x,part.y, part.radius, 0, Math.PI*2);

          ctx.closePath();

          ctx.fillStyle = "white";

          ctx.fill();

       }

    }

</script>

</body>

</html>

      在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器視窗中看到如圖8所示的動畫。

 

圖8  下雪了


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 系統提供的排序方法(一般情況下,我們需要自己進行編寫排序演算法) reverser( ) 逆向排序 格式: 數組.reverse( ) let arr = [1,2,3,4,5]; arr.reverse(); console.log(arr);//列印結果為[5,4,3,2,1] sort( ) 將 ...
  • 一 通過迴圈按行順序為5*5的二維數組,a賦值1到25的自然數, 二 然後輸出該數組的左下半三角形,試編程。 [ 1, 2, 3, 4, 5 ] [ 6, 7, 8, 9, 10 ] [ 11, 12, 13, 14, 15 ] [ 16, 17, 18, 19, 20 ] [ 21, 22, 23 ...
  • <style> html{ display: none; <!--開始的時候讓頁面全部隱藏--> } </style> <script> function Web_Presentation() { document.querySelector('html').style.display='block ...
  • 在前面隨筆介紹了ABP+Vue前後端的整合處理,包括介紹了ABP的後端設計,以及前端對ABP介面API的ES6的封裝,通過JS的繼承類處理,極大減少了重覆臃腫的代碼,可以簡化對後端API介面的封裝,而且前端使用Element組件,很好展示API獲得的數據,通過在界面中展示樹狀列表,以及表格列表數據,... ...
  • 01 興趣 興趣是學習的第一老師。如果打算進入IT行業,找到自己興趣所在是最好的。 很多小伙伴對前後端分得不是很清楚,確認興趣方式如下: 通過網路視頻資源短期學習 線下培訓機構申請短期試學 一部分小伙伴試學後仍然感覺前後端差不多,很難判斷自己的興趣是前端還是後端。在這裡“興趣”的定義不是試學後滿心歡 ...
  • WEB學習路線2020完整版+附視頻教程,適合初學者的最新WEB前端學習路線彙總! ...
  • 以下純屬個人觀點和建議,肯定是有局限性的,但是也希望能給你帶來一些幫助。 我們儼然能感受到前端崗位現在已經發展成了最重要的研發崗位之一,所以多我們提出的要求也就越來越高了。所以我們需要的也就不僅僅只是掌握css、html、JavaScript了,但是這三大件一直都是前端的根本,這一點從未改變,而這三 ...
  • 1. 引言 1.1. 背景 隨著時代的進步,社會的發展,人們的生活形式與習慣也越來越多樣化,出行成為了人們生活中的一個重要組成部分,而客車成為許多人出行選擇的交通工具。面對巨大數量的乘客的購票需要,客車站就要選擇使用先進的管理方法來實現方便、快捷的售票、退票等方面的票務管理。隨著電腦的普及,信息處 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...