1.一個沿圓周運動的圓圈
一個半徑為size的圓圈以畫布的中心(canvas.width/2,canvas.height/2)為起點,沿着一個圓周運動。編寫如下的HTML代碼。

<!DOCTYPE html> <html> <head> <title>沿圓周運動的圓圈</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); document.body.appendChild(canvas); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); var angle =360; var pos = [canvas.width/2,canvas.height/2]; var size = 10; var speed = 1; var curve = 0.5; var color = 'rgba(69,204,255,.95)'; function draw () { var radians = angle*Math.PI/180; pos[0] += Math.cos(radians)* speed; pos[1] += Math.sin(radians)* speed; angle += curve; ctx.strokeStyle = color; ctx.beginPath(); ctx.arc(pos[0],pos[1],size,0,2*Math.PI); ctx.stroke(); window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw); </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器窗口中呈現出如圖1所示的動畫效果。
圖1 沿圓周運動的一個圓圈
由圖1可知,圓圈運動的起點(canvas.width/2,canvas.height/2)位於運動所沿的圓周上angle==360°的位置。
2.兩個沿圓周運動的圓圈
在畫布中放置兩個圓圈,兩個圓圈的起點均位於畫布中心(canvas.width/2,canvas.height/2),一個圓圈從所沿圓周的45°處沿圓周運動,另一個圓圈從所沿圓周的135°處沿圓周運動。編寫如下的HTML代碼。

<!DOCTYPE html> <html> <head> <title>沿圓周運動的圓圈</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); document.body.appendChild(canvas); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); var angle1 =45; var angle2 =135; var pos1 = [canvas.width/2,canvas.height/2]; var pos2 = [canvas.width/2,canvas.height/2]; var size = 10; var speed = 1; var curve = 0.5; var color1 = 'rgba(69,204,255,.95)'; var color2 = 'rgba(255,212,50,.95)'; function draw () { var radians = angle1*Math.PI/180; pos1[0] += Math.cos(radians)* speed; pos1[1] += Math.sin(radians)* speed; angle1 += curve; radians = angle2*Math.PI/180; pos2[0] += Math.cos(radians)* speed; pos2[1] += Math.sin(radians)* speed; angle2 += curve; ctx.strokeStyle = color1; ctx.beginPath(); ctx.arc(pos1[0],pos1[1],size,0,2*Math.PI); ctx.stroke(); ctx.strokeStyle = color2; ctx.beginPath(); ctx.arc(pos2[0],pos2[1],size,0,2*Math.PI); ctx.stroke(); // fade(); window.requestAnimationFrame(draw); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); } window.requestAnimationFrame(draw); </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器窗口中呈現出如圖2所示的動畫效果。
圖2 兩個沿圓周運動的圓圈
為了展示圓圈運動的軌跡,我們在函數draw()的函數體中,最后一行語句前加上調用語句“fade();”,編寫fade()函數如下:
function fade ()
{
ctx.beginPath();
ctx.fillStyle = 'rgba(0, 0, 0, .03)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
這樣,圓圈運動軌跡帶長尾效果。在瀏覽器中呈現出如圖3所示的動畫效果。
圖3 兩個沿圓周運動的圓圈(帶長尾效果)
3.更多沿圓周運動的圓圈
如果要在畫布中讓num個圓圈沿圓周運動呢?為此,將圓圈抽象為粒子對象Particle,該對象有圓圈在所沿圓周上的起始位置angle、圓圈運動的當前位置pos(初始值為畫布中心[canvas.width/2,canvas.height/2])、圓圈大小size、運動速度speed、運動角度變化量curve和圓圈顏色color等屬性;為該對象定義move和draw兩個方法,分別完成圓圈的位置變化和圓圈繪制操作。
為設定方便起見,給沿圓周運動的圓圈預設置4個參數,用變量config來表示。config.num、config.size 、config.speed和config.curve分別表示4個參數分量。其中,config.num表示畫布中參與運動的圓圈個數,由它計算出圓圈在所沿圓周上的起始位置angle。
編寫的HTML文件如下。

<!DOCTYPE html> <html> <head> <title>沿圓周運動的圓圈(給定4個參數)</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); var particles = []; var colors = [ 'rgba(69,204,255,.95)', 'rgba(73,232,62,.95)', 'rgba(255,212,50,.95)', 'rgba(232,75,48,.95)', 'rgba(178,67,255,.95)' ]; var config = {}; config.num = 5; config.size = 2; config.speed = 1; config.curve = 0.5; createParticles() window.requestAnimationFrame(draw); function createParticles() { var n = config.num; for (var i=0; i<n; i++) { var angle = (360/n)*(i+1); particles.push(new Particle(angle,colors[i%5])); } } function draw () { for (var i=0; i<particles.length; i++) { var p = particles[i]; p.move(); p.draw(); } fade(); window.requestAnimationFrame(draw); } function Particle (angle,color) { this.angle = angle; this.size = config.size; this.speed = config.speed; this.color = color; this.curve = config.curve; this.pos = [canvas.width/2, canvas.height/2]; } Particle.prototype.move = function() { this.angle += this.curve; var radians = this.angle*Math.PI/180; this.pos[0] += Math.cos(radians)*this.speed, this.pos[1] += Math.sin(radians)*this.speed; } Particle.prototype.draw = function () { ctx.strokeStyle = this.color; ctx.beginPath(); ctx.arc(this.pos[0],this.pos[1],this.size,0,2*Math.PI); ctx.stroke(); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); } </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器窗口中呈現出如圖4所示的動畫效果。
圖4 沿圓周運動的圓圈(num=5,size=2,speed = 1,curve = 0.5)
為4個參數設定不同的值,可以呈現出不同的動畫效果。給出3組不同值的設定,呈現的動畫效果分別如圖5、圖6和圖7所示。為避免圖形文件過大,下列的動畫過程均只錄制一個片段。完整的動畫演示過程請讀者自己打開HTML文件運行程序觀看。
圖5 沿圓周運動的圓圈(num=80,size=4,speed = 1,curve = 0.5)
圖6 沿圓周運動的圓圈(num=8,size=16,speed = 1.8,curve = 1.8)
圖7 沿圓周運動的圓圈(num=90,size=100,speed = 2,curve =1)
由圖4~圖7可知,參數speed 和curve決定了圓圈運動的軌跡。上面代碼中,各個圓圈的參數speed 和curve均相同。能否讓各個運動的圓圈的參數speed 和curve不同,這樣它們的運動軌跡也不同,呈現出更多的變化呢?
一個簡單的辦法是讓參數speed 和curve在某個區間范圍內隨機取值。
例如,修改config參數的設置如下:
config.num = 80;
config.size = 300;
config.speed =[1,10];
config.curve = [-0.5,0.5];
修改function Particle (angle,color)如下:
function Particle (angle,color)
{
this.angle = angle;
this.size = config.size;
this.speed = rand(config.speed[0],config.speed[1]);
this.color = color;
this.curve = rand(config.curve[0],config.curve[1]);
this.pos = [canvas.width/2, canvas.height/2];
}
增加在區間[min,max]中取隨機值的函數如下:
function rand(min, max)
{
return Math.random()*(max-min)+min;
}
其余部分保持不變,則在瀏覽器窗口中呈現出如圖8所示的動畫效果。這個動畫效果有點炫酷喲!
圖8 沿圓周運動的圓圈(num=80,size=300,speed =1~10,curve =-0.5~0.5)
4.可設置參數的沿圓周運動的圓圈
由圖4~圖8可知,不同的參數設定,沿圓周運動的圓圈所呈現的動畫效果不同。為此,我們提供文本框輸入預設數值的方式對4個參數的值進行設定,設定完成后,單擊“Go!”按鈕,按設定的參數進行動畫效果的呈現。
編寫的HTML代碼如下。

<!DOCTYPE html> <html> <head> <title>沿圓周運動的圓圈(可設置參數)</title> <style> form { position:absolute; top:0; left:0; z-index:100; background-color:rgba(200,200,200,.8); padding:8px; font-size:90%; } form input[type=text] { width:30px; border:1px solid #000; text-align:center; } form button { margin:4px auto; border:1px solid #000; display:block; } </style> </head> <body> <form id="settings" onsubmit="return false"> Particles<br/> <input type="text" id="inBubblesMin" value="150"/> To <input type="text" id="inBubblesMax" value="150"/><br/> Size<br/> <input type="text" id="inSizeMin" value="2"/> To <input type="text" id="inSizeMax" value="2"/><br/> Speed<br/> <input type="text" id="inSpeedMin" value="1"/> To <input type="text" id="inSpeedMax" value="1"/><br/> Curve<br/> <input type="text" id="inCurveMin" value=".5"/> To <input type="text" id="inCurveMax" value=".5"/><br/> <button id="btnClear">Clear</button> <button id="btnSet">Go!</button><br/> </form> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var particles = []; var colors = [ 'rgba(69,204,255,.95)', 'rgba(73,232,62,.95)', 'rgba(255,212,50,.95)', 'rgba(232,75,48,.95)', 'rgba(178,67,255,.95)' ]; var config = {}; var settings = document.getElementById('settings'); start(); window.requestAnimationFrame(draw); function createParticles() { var n = rand(config.num[0],config.num[1]); for (var i=0; i<n; i++) { var angle = (360/n)*(i+1); particles.push(new Particle({ angle:angle, size:rand(config.size[0],config.size[1]), speed:rand(config.speed[0],config.speed[1]), color:colors[i%5], curve:rand(config.curve[0],config.curve[1]) })); } } function draw () { for (var i=0; i<particles.length; i++) { var p = particles[i]; p.move(); p.draw(ctx); } fade(); window.requestAnimationFrame(draw); } function Particle (options) { this.angle = options.angle; this.size = options.size; this.speed = options.speed; this.color = options.color; this.curve = options.curve; this.pos = [canvas.width/2, canvas.height/2]; } Particle.prototype.move = function() { this.angle += this.curve; var radians = this.angle*Math.PI/180; this.pos[0] += Math.cos(radians)*this.speed, this.pos[1] += Math.sin(radians)*this.speed; } Particle.prototype.draw = function (ctx) { ctx.strokeStyle = this.color; ctx.beginPath(); ctx.arc(this.pos[0],this.pos[1],this.size,0,2*Math.PI); ctx.stroke(); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); } function clear () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); particles.length = 0; } function start() { config.num = [parseFloat(settings.inBubblesMin.value), parseFloat(settings.inBubblesMax.value) ]; config.size = [parseFloat(settings.inSizeMin.value), parseFloat(settings.inSizeMax.value)]; config.speed = [parseFloat(settings.inSpeedMin.value), parseFloat(settings.inSpeedMax.value)]; config.curve = [parseFloat(settings.inCurveMin.value), parseFloat(settings.inCurveMax.value)]; createParticles(); } settings.btnSet.addEventListener("click", start); settings.btnClear.addEventListener("click", clear); function rand(min, max) { return Math.random()*(max-min)+min; } </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,可以在瀏覽器窗口中呈現出如圖9所示的動畫效果。
圖9 沿圓周運動的圓圈(單擊一次Go!按鈕)
在頁面中,單擊“Clear”按鈕,會清屏,同時置粒子數組的長度為0,相當於頁面中不再有沿圓周運動的圓圈。
單擊“Go!”按鈕,會讀取設置的參數值,同時調用createParticles();向粒子數組中添加運動的圓圈。注意:是添加,若數組中原來有運動的圓圈,則原來運動的圓圈會繼續運動。這樣,多次單擊“Go!”按鈕,會呈現出更多有變化的動畫效果。
例如,圖9的動畫效果是150個運動的圓圈構成一個大圓環收縮效果。若按一定時間間隔單擊兩次“Go!”按鈕,應該會呈現出2個大圓環交替收縮的動畫效果,如圖10所示。
圖10 沿圓周運動的圓圈(單擊兩次Go!按鈕)
多次單擊“Go!”按鈕添加運動圓圈的功能設定很有意思了。這意味着我們可以將上面的動畫效果進行組合。圖10的動畫效果實質是兩個圖9所示動畫效果的組合。
例如,設定num=150,size=2,speed = 1,curve = 0.5后,單擊“Go!”按鈕,呈現出如圖9所示的動畫效果;再設定num=8,size=16,speed = 1.8,curve = 1.8,單擊“Go!”按鈕(呈現如圖6所示的動畫效果)后,圖6和圖9的動畫效果組合起來,呈現出如圖11所示的動畫效果。
圖11 兩種動畫效果的組合