每周一點canvas動畫代碼文件
在上一章中,我們介紹了很多在三維環境下物體的運動效果。雖然環境是三維的了,但不管是ball.js,還是tree.js總的來說還是二維的物體。這一章我們就介紹怎樣使用canvas API來創建三維的物體。
從本節開始,文章的前半部分我們繼續介紹動畫的一些理論知識。後半部分我會運用前面章節中的知識點,分享一些DEMO動畫。動畫的源碼會放到share文件夾下。
1、點和線
在上一章中,連線隨機球體間的位置可以形成如下的效果,具體代碼在line-3d-1.html中。這裡我們仍舊使用的是ball3d.js文件。
效果似乎還不錯。但是,如果我們想要其中的線條,怎麼辦呢?。一個很好的方法是設置ball.radius = 0!ok,我們看看效果如何。
目標達成,所有的球體的半徑都變成了0,形成了我們想要的效果。但如果想要創造一些更加複雜的3D物體,總不能所有的點都是用球體來佔位吧!下面是我們定義的ball3d的屬性,對於點來說,仔細觀察你就會發現,這裡面有很多冗餘的屬性。
function Ball3d(radius,color){ if(radius === undefined) {radius = 40;} //默認半徑,點是無大小的!kill if(color === undefined){color = '#00ff00';} //大小都沒有了,還要顏色!kill this.x = 0; //用於確定二維的坐標 this.y = 0; this.xpos = 0; //用於在三維環境中的位置變換,最終還是反應到二維坐標上!合併 this.ypos = 0; this.zpos = 0; this.vz = 0; //速度kill this.vx = 0; this.vy = 0; this.radius = radius; //kill this.rotation = 0; //單個點無興趣!kill this.mass = 1; //點無質量, kill this.scaleX = 1; //大小都沒了,還要scale有何用!kill this.scaleY = 1; this.name = ""; //kill this.color = utils.parseColor(color); //kill this.lineWidth = 1; //kill this.visible = true; //不可見多餘!kill}
把不要的屬性全部kill掉,現在我們創建一個新的類文件叫point3d.js。屬性經過精簡,並且集成了透視(perspective)和坐標旋轉等功能。具體代碼如下,首先看基本屬性:
function Point3d(x, y ,z){ this.x = (x === undefined) ? 0 : x; //位置 this.y = (y === undefined) ? 0 : y; this.z = (z === undefined) ? 0 : z; this.fl = 250; //焦距 this.vpX = 0; //消失點 this.vpY = 0; this.cX = 0; //中心點 this.cY = 0; this.cZ = 0; }
然後是各種方法。
設置消失點Point3d.prototype.setVanishingPoint = function(vpX, vpY){ this.vpX = vpX; this.vpY = vpY;}
設置中心點Point3d.prototype.setCenter = function(cX, cY, cZ){ this.cX = cX; this.cY = cY; this.cZ = cZ;}
旋轉X, Y ,ZPoint3d.prototype.rotateX = function(angleX){ var cosX = Math.cos(angleX), sinX = Math.sin(angleX), y1 = this.y * cosX - this.z * sinX, z1 = this.z * cosX + this.y * sinX; this.y = y1; this.z = z1;}Point3d.prototype.rotateY = function(angleY){ ...}Point3d.prototype.rotateZ = function(angleZ){ ...}
計算屏幕坐標Point3d.prototype.getScreenX = function(){ var scale = this.fl / (this.fl + this.cZ); return this.vpX + (this.cX + this.x) * scale;}Point3d.prototype.getScreenY = function(){ var scale = this.fl / (this.fl + this.cZ); return this.vpY + (this.cY + this.y) * scale;}
ok,大功告成!具體代碼請查看point3d.js,通過它我們就能創建任意我們想要的圖形。圖形的創建相對來說比較枯燥,我們放到下一節來講,下面我們介紹本節的分享DEMO。
2.水波動畫
水波動畫用到的知識點在《每周一點canvas動畫》——三角函數(2)中的平滑運動部分,主要運用三角函數來控制某一個點位置的移動。由於三角函數sin,cos的值域處於[-1, 1]之間,所以讓它乘以一個比較大的數,如100,我們就可以得到一個比較大的值域變化區間[-100, 100]。同時,值的變化並非是線性的,我們用這一特性來形成平滑運動。DEMO圖如下:
最上面的按鈕控制波浪的運動速度(Speed), 波的高度(Height),波峰之間的寬度(Width)。下面有3個顏色按鈕,控制水波的顏色。
水波的形成有很多種方法,我們這裡是用豎直線條構成,也就是說如果canvas的寬度為500,那麼我們就用500根線條來組成。當然除了線條還可以使用矩形或是比較寬的線條,只不過形成的波面不會如此平滑,會出現鋸齒。下面我們看下核心代碼:
//繪製函數function draw(angle){ for(var i =0; i< lineNum; i++){ var point={ x: i, y: waterLine + Math.sin(angle+speed)*waterTop }; ctx.beginPath(); ctx.lineWidth=1; ctx.strokeStyle= color; ctx.moveTo(point.x,500); ctx.lineTo(point.x, point.y); ctx.stroke(); angle += angleChange } speed += speedChange; }
核心代碼就這麼簡單,在每一幀中我們都繪製lineNum數量的線條,每一根線條頂點的Y坐標,我們通過waterLine+Math.sin(angle)*waterTop來控制。這樣由於線條的高度不同,總體的外邊界就形成了sin波形的包絡。
雖然,線條的高度出來了。那麼,如何讓它有運動的效果呢?這裡,我們思路是在下一幀改變每根線條的高度值(通過改變speed值)。這樣在每一幀每一根線條都發生高低錯落的變化,反映到整體上就是波形向前或向後運動。具體代碼請查看share/wave.html
ok!本節我們就到這裡!see you!
原文連結
https://segmentfault.com/a/1190000007003958
原作者:
我仍舊在這裡