嗨!大家好,到了每個禮拜的發文時間了(才怪這禮拜已經四篇了XD),今天要來說說[筆記][HTML][JavaScript]canvas的基本用法(3)-最後用滑鼠互動動畫做個結尾!這篇文章裡稍微提到的極座標。
好的,那什麼是極座標?讓我們先看看從維基百科裡查到的解釋:
極座標系(英語:Polar coordinate system)是一個二維座標系統。該座標系統中任意位置可由一個夾角和一段相對原點—極點的距離來表示」
OK,讓我們搭配圖形,來簡單說說這是怎麼一回事:
上圖中的黑色橫線是X
軸、直線是Y
軸,藍點是座標為(0,0)
的原點,以原點當圓心畫一個半徑為r
的圓形,這時候我們在圓邊上的任一點上標記一個綠點,也就是上文說的極點,將極點與圓心相連畫出橘色與紫色的線,當然,這兩條線的長度也是圓的半徑r
,仔細看一下,這兩條線和X
軸之間的夾角不同,會導致線的方向也不一樣,在三角函數中中我們稱這一角度為θ
他的英文是theta
,唸做夕塔
XD。
那接著我們如果要取得某一極點的座標該怎麼做呢?這就要吐出剛剛提到的三角函數了,不過大家不要緊張,我們只需要知道兩種而已,那就是正弦sin
和餘弦cos
,以下會用最簡單的方式來講解這兩個函數求出來的值,那還是先上圖:
這是一張非常簡單的圖,圖中藍點是我們的圓點,t
是夾角θ
,而下邊x
是X
軸距離原點的距離,右邊的y
則是Y
軸距離原點的距離,在右上方的綠點則是極點,所以我們可以透過三角型可以得知,極點的座標是(原點的X軸座標 + x,原點的y軸座標 + y)
,但我們該怎麼知道x
和y
的數值各是多少?先看看以下關於sin
和cos
的公式:
sinθ = y / r
cosθ = x / r
因為除法太不親民了,所以我們把,公式中的x和三角函數交換位置,轉換成乘法:
y = sinθ * r
x = cosθ * r
看起來是不是簡單多了!只要我們知道半徑r
和sinθ
及cosθ
,就有辦法取得任一極點的座標,也就是今天的主題極座標。
也許你會想說,我知道半徑r
,但我對那個sinθ
和cosθ
實在不曉得該怎麼辦才好,放心在JavaScript
中這兩個函數已經妥妥的準備好!剩下的就是動手實做!讓我們來做個簡單的小例子吧!
以上一次的太陽為例子來重新繪製他身邊的光線,我先刪減了背景顏色變化和之前繪製光線的部分,只留下太陽的本體,程式碼如下:
HTML
<canvas id="myCanvas"></canvas>
JavaSript
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
//紀錄滑鼠位置
let mouse = {
x : 0,
y : 0,
};
//監聽滑鼠事件
window.addEventListener('mousemove',(event) => {
mouse.x = event.pageX;
mouse.y = event.pageY;
});
//一個繪製的function
const draw = () =>{
//把視窗大小重新設定給canvas
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
ctx.clearRect(0, 0, canvas.width, canvas.height);
//之後繪製太陽
ctx.beginPath();
ctx.arc(mouse.x,mouse.y,30,0,Math.PI*2);
ctx.strokeStyle="#FF5511";
ctx.stroke();
ctx.fillStyle="#FFFF00";
ctx.fill();
//繪製光芒線條
lightLine();
};
//繪製光芒線條的function
const lightLine = () =>{
};
//每隔50毫秒重新繪製一次
setInterval('draw()',50);
這時候我們的太陽會回到上圖,只有本體的樣子,再來會專注在lightLine
function中,但在這之前先複習一下[筆記][HTML][JavaScript]canvas的基本用法(1)-來繪製一些簡單的圖形吧!講的兩件事情
JavaScript
中的Math.PI
是代表角度180度。複習完畢後,就來畫光線吧!先整理一下剛剛講過的東西,從原點開始到任一極點的線段我們可以把它當成半徑r
,而這時候的原點,是太陽的中心;太陽的中心又是跟著滑鼠跑的,所以原點為mouse
物件中的x
和y
,接著試想一下太陽的半徑是30
,光線又一定會超越太陽本身,所以r
的長度會大於30,這裡先給定60,有了原點、半徑後,我們還需要角度,不過現階段我們先設角度為0,繪製出如同X軸的右線:
JavaScript
//繪製光芒線條的function
const lightLine = () =>{
//開始繪圖
ctx.beginPath();
//開始點為原點,滑鼠目前的所在座標
ctx.moveTo(mouse.x,mouse.y);
//從原點到某一極座標,用文章開頭說的公式帶入數字,設角度為0,r為60,取得X軸及Y軸
//求X的公式為x = cosθ * r
let X = Math.cos(0) * 60;
//求y的公式為x = sinθ * r
let Y = Math.sin(0) * 60;
//上方取得的X及Y為從原點到某一極點的距離,所以我們把原點的所在座標加上該數值
ctx.lineTo(mouse.x + X,mouse.y + Y);
ctx.stroke();
};
如此一來就能夠畫出從原點到某一極點的線段了!
看了結果後可能你會覺得奇怪,線條的起始點不是應該要距離太陽有些距離的嗎?沒錯!所以我們稍微想一下,目前設定的起始點是原點,如果要讓他在太陽的本體外面開始,那要改變哪個數值呢?
嘿嘿!對的!就是半徑,既然可以讓結束的點用極座標控制在太陽本體之外,那一定也可以讓起始點做到一樣的事情,剛剛預設結束點的半徑r
是60,那我們讓起始點的半徑r
大於太陽的半徑30一點點,就設定為40。以下程式:
JavaScript
const lightLine = () =>{
ctx.beginPath();
//把r設為40取x軸和y軸距離原點的距離
let X = Math.cos(0) * 40;
let Y = Math.sin(0) * 40;
//用原點加上該距離
ctx.moveTo(mouse.x + X,mouse.y + Y);
//結束點不變
X = Math.cos(0) * 60;
Y = Math.sin(0) * 60;
ctx.lineTo(mouse.x + X,mouse.y + Y);
ctx.stroke();
};
經過上段程式的調整我們會得出上面的太陽,距離太陽一些間隔的線段,這就是我們要的,但還不完全,我們要能夠去畫出每一個角度的線條,並用迴圈繪製每條線段。
那該怎麼得到每個角度呢?目前我們知道的只有代表180度的Math.PI
,如果今天要得到60度,可以用360度,也就是先把Math.PI*2
(180度乘上2)後在除於6來處理,但是如果要取的角度是17度呢?147度?273度?該怎麼辦?就用比例原則吧!
所謂的比例原則,就是先得出該角度占了360度的多少。以17度為例,用17/360來算出該角度在360度中的比例,大約是0.047222...
左右,那在以這個數字去乘回代表360度的Math.PI*2
就有辦法取得任一圓的任一角度!我們把這個公式帶進程式中:
JavaScript
const lightLine = () =>{
ctx.beginPath()
//設定一個變數為角度
let t = 0;
//假設我們要畫夾角為17度的線段
t = 17
/*把計算cosθ和sinθ的切出來
並以角度t除上360度取得比例後在乘上Math.PI*2獲得角度
*/
let cosT = Math.cos((t/360) * (Math.PI*2))
let sinT = Math.sin((t/360) * (Math.PI*2))
let X = cosT * 40;
let Y = sinT * 40;
ctx.moveTo(mouse.x + X,mouse.y + Y);
X = cosT * 60;
Y = sinT * 60;
ctx.lineTo(mouse.x + X,mouse.y + Y);
ctx.stroke();
};
如上圖,會微妙的發現線段往下偏移了17度。那現在各位大大們應該已經了解極座標了!剩下光芒線條,就可以直接用迴圈處理:
const lightLine = () =>{
ctx.beginPath()
//把角度t放到迴圈中,從0開始到360度,每隔20度就畫繪製一條光線
for(let t=0;t<360;t+=20){
let cosT = Math.cos((t/360) * (Math.PI*2))
let sinT = Math.sin((t/360) * (Math.PI*2))
let X = cosT * 40;
let Y = sinT * 40;
ctx.moveTo(mouse.x + X,mouse.y + Y);
X = cosT * 60;
Y = sinT * 60;
ctx.lineTo(mouse.x + X,mouse.y + Y);
ctx.stroke();
};
};
登愣!使用極座標繪製的太陽完成了!有沒有覺得用這種方式繪製出來的光線比較自然XD,如果要增加或減少線條的話,主要是在t+=20
這個地方做設置,如果希望光線密集一點,就讓間隔的角度小一些,如果希望他寬鬆一點,就加大間隔,小弟我在此附上CodePen連結,如果有興趣的話可以試試看他的變化,基本上就和上次的差不多XD。
終於找了個時間研究一下極座標這玩意兒,也沒想到原來三角函數這麼簡單XD,這篇應該不會是Canvas
的最後一篇,只是之後可能不會繼續用canvas的基本用法基本用法
這個系列名稱了,因為之後的可能一點都不基本,哈哈哈,不過如果有還是會繼續加上去啦!
之後我會打算做一個小遊戲,就之前參加六角學院那個活動的其中一個題目,雖然當時有先交了最低標準的作品出去,但還是會想要把他完成,如果好奇的話可以點這裡看設計稿,剛剛看了一下還是覺得很難XD,如果各位大大有什麼建議,或經驗分享還請留言指教我了,小弟我會感激不盡的
那最後謝謝大家的觀看!如果文章中有任何建議、解釋錯誤或是不清楚的地方,都可以留言告訴我,我會盡快修改的!謝謝大家!
參考文章: