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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...