上文我們講到了畫一條線,畫矩形,寫文字,總算是有了一個好的開頭,如果還沒有看的同學出門左轉,先看看那篇,這裡就不多做敘述了,接下來我們看比較復雜的一些屬性和方法!
講之前呢,我還是想溫習一下,畢竟上文還有幾個屬性沒有講到,那我們從畫三角形開始吧!
如果看了上文,機智的少年肯定會想到,三角形,多簡單啊,無非是比直線多一個點,於是這少年就開始動手了:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.stroke();
呀呵,怎麼是一個折線,三角形不是只有三個點嗎?是不是因為沒有閉合呢?那我再加一個點:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.lineTo(50,50); ctx.stroke();
哈哈,果然機智如你啊!這個思路其實是正解的,三角形就是這麼簡單,其實還有一種方式可以畫三角形,只需3個點,那就是我們要介紹的:
closePath() 閉合路徑
有閉合就是開始,一般來說他們是成雙成對的
beginPath() 開始路徑
這對活寶的用法一般是:
ctx.beginPath(); ctx.closePath();
先開始路勁,裡面寫你要繪制的內容,然後結束路勁,相當於是一個盒子已經封箱了,這樣做有個好處就是可以避免繪制過程中的樣式污染,你不知道怎麼污染?好吧,看下面:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); //第一個三角 ctx.strokeStyle = 'red'; ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.lineTo(50,50); ctx.stroke(); //第二個三角 ctx.strokeStyle = 'green'; ctx.moveTo(150,50); ctx.lineTo(200,100); ctx.lineTo(150,200); ctx.lineTo(150,50); ctx.stroke();
如圖,如果我本來是想讓第一個三角的顏色為紅色,第二個為綠色,但是現在的結果卻都是綠色,而且眼尖的同學還看到,第一個三角感覺有2個顏色,顏色也特別的深,感覺是疊了2個三角,你沒看到?好,我們改改,你在看:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); //第一個三角 ctx.strokeStyle = 'red'; ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.lineTo(50,50); //ctx.stroke(); //第二個三角 ctx.strokeStyle = 'green'; ctx.moveTo(150,50); ctx.lineTo(200,100); ctx.lineTo(150,200); //ctx.lineTo(150,50); ctx.stroke();
我們先不畫第一個三角,也不畫第二個三角的左邊一邊,然後看一下:
第一個三角沒有雙重色了,說吧繪制了2次,一次紅,一次綠,去掉了重繪,後面的顏色也將前面的顏色污染了,這不是我們想要的,這污染,你應該明白了吧!
那我們使用那對活寶看看:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); //第一個三角 ctx.beginPath(); ctx.strokeStyle = 'red'; ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.lineTo(50,50); ctx.closePath(); ctx.stroke(); //第二個三角 ctx.beginPath(); ctx.strokeStyle = 'green'; ctx.moveTo(150,50); ctx.lineTo(200,100); ctx.lineTo(150,200); ctx.lineTo(150,50); ctx.closePath(); ctx.stroke();
這才是我們想要的嘛,你玩你的,我玩我的,互不干擾,(你說畫三角只需3個點的呢,吹牛B吧,你看你都是用的4個點),哦,對。
closePath() 方法創建從當前點到開始點的路徑,這是對此方法的描述,也就是說,使用這個方法,就能將畫筆移到beginPath()的位置,這樣才能結束畫布,所以照這個理論,當畫三角時,畫到第三個點時,我們用closePath()方法讓畫筆回到起點,再畫線,是不是就閉合了,看看效果:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.strokeStyle = 'red'; ctx.moveTo(50,50); ctx.lineTo(100,100); ctx.lineTo(50,200); ctx.closePath(); ctx.stroke();
看,只有三個點,不是折線吧,後面要講的什麼扇形圖,不規則圖形都可以用此技能,妥妥的!
嗨,也不過如此,你這線條都是一像素的,又不能跟孫悟空的金箍棒一樣,要大變大,要小變小,哼,誰說的,哥有神器在手,天下無敵!
我的法寶就是:
lineWidth 設置或返回當前的線條寬度
怎麼用?哥給一個跟金箍棒:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var timer = null; var num = 1; ctx.moveTo(150,50); ctx.strokeStyle = 'gold'; setInterval(function(){ if(num == 100){ clearInterval(timer); num=1; }else{ num++; }; ctx.lineTo(150,100+num*2); ctx.lineWidth = num; ctx.stroke(); },100)
金箍棒,大,大,大,大,在大點,哈哈哈~~~
咳咳,嚴肅點,有此神器,我們就可以修改任何線框,線條的線條寬度了,比如說空心三角形,空心矩形,當然,空心文字你就不要問我了,我不知道~
關於線條,還有另外2個屬性:
lineJoin 兩線交叉的拐角類型
參數:
miter : 尖角 默認
bevel : 斜角
round : 圓角
什麼意思,那就用空心矩形為例:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.beginPath();
ctx.lineJoin = 'miter';
ctx.strokeRect(100,10,80,80);
ctx.closePath();
ctx.beginPath();
ctx.lineJoin = 'round';
ctx.strokeRect(100,110,80,80);
ctx.closePath();
ctx.beginPath();
ctx.lineJoin = 'bevel';
ctx.strokeRect(100,210,80,80);
ctx.closePath();
右側為折線效果
配合折線效果,還有一個屬性:
miterLimit 規定最大斜接長度。什麼意思?看看右邊的這個折線圖,最下面那組的尖尖角,這個就是斜接,意思通俗意思就是規定那個尖尖角的長度,如果尖尖角的長度小於miterLimit 的值,則正常顯示,如果大於的話,就會被截掉一部分,其形狀就跟lineJoin='bevel'一樣一樣的,且此方法只對lineJoin="miter" 默認值的時候才起作用,給個形象的例子吧:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.lineWidth=10; ctx.lineJoin="miter"; ctx.beginPath(); ctx.miterLimit=19; ctx.moveTo(20,20); ctx.lineTo(150,27); ctx.lineTo(20,34); ctx.stroke(); ctx.beginPath(); ctx.miterLimit=18; ctx.moveTo(20,120); ctx.lineTo(150,127); ctx.lineTo(20,134); ctx.stroke();
ctx.beginPath();
ctx.lineJoin="bevel";
ctx.moveTo(20,220);
ctx.lineTo(150,227);
ctx.lineTo(20,234);
ctx.stroke();
如圖,當miterLimit 的值大於等於19時,尖尖角正常顯示,小於18時,尖尖角被截斷了,效果跟設置lineJoin='bevel'是一樣的,暫不知道會有什麼作用,待以後來發掘!
另一個:
lineCap 設置或返回線條的結束端點樣式 注意,這是設置線條的哦!
參數:
butt 默認。向線條的每個末端添加平直的邊緣。
round 向線條的每個末端添加圓形線帽。
square 向線條的每個末端添加正方形線帽。
什麼意思?線條嘛,我們還是以金箍棒為例,算了,還是用線條吧(看到金箍棒我就想笑了);
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.lineWidth = 10; ctx.beginPath(); ctx.lineCap = 'butt'; ctx.moveTo(50,50); ctx.lineTo(200,50); ctx.stroke(); ctx.beginPath(); ctx.lineCap = 'round'; ctx.moveTo(50,100); ctx.lineTo(200,100); ctx.stroke(); ctx.beginPath(); ctx.lineCap = 'square'; ctx.moveTo(50,150); ctx.lineTo(200,150); ctx.stroke();
可以看到,後面2個比第一個要長一點,具體長多少呢?畫一個圖示意一下:
圓角和方腳的原理其實是這樣的,很明顯多出的一部分的寬度就是線條的一半的長度,所以要精確計算其長度,此小細節需謹記!
現在我們來講講畫圓及其相關的圖形:
arc(x,y,r,sAngle,eAngle,counterclockwise)
什麼意思? x,y表示坐標點表示圓心坐標,r表示半徑,sAngle表示開始弧度,eAngle表示結束弧度,counterclockwise表示順時針還是逆時針方式,默認為順時針false,逆時針為true
注意,這裡的角度是用弧度表示的,不是直接寫角度,那問題來了,一般我們知道一個圓弧是多少度,怎麼知道它是多少弧度呢?總感覺弧度太抽象,嗯嗯,我也有同感,那我們就來科普一下弧度的算法吧,列幾個公式(初中,高中的數學,都還給老師了):
1弧度 = r;
360° = 2∏;
周長C = 2∏r;
那麼一周的弧度數 = 2∏r/r = 2∏ = 360°
則1° = 2∏*1°/360° = ∏*1° /180° (弧度)
90° = ∏*90° /180° (弧度)
圓的初始位置是在最右邊,跟我們自己手繪圓的起點有那麼一點點的不一樣,默認是順時針方向,那角度就應該是如圖所示的角度,要是還不清楚的話,我們畫2半圓,分別表示順時針和逆時針,這樣就應該清楚了,哦,需要說明的一點就是,畫用的方法跟畫直線和矩形框的原理是一樣的,只是畫出了路徑,並沒有添墨水,仍需用黑白雙煞:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.arc(80,100,50,0,180*Math.PI/180,false); ctx.stroke();
ctx.beginPath(); ctx.arc(200,100,50,0,180*Math.PI/180,true); ctx.stroke();
js裡面是沒有∏的,你懂的,但是有函數Math.PI,咦,這裡為什麼是圓弧而不是半圓啊,如果我要畫一個半圓怎麼弄呢?哈哈~,還記得上面三角形的那個折線嗎?這個是一個原理,只是圖形沒有閉合而已,用closePath()就可以閉合了。
畫一個扇形看看,這裡我就閉合圖形哈:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.arc(80,100,50,30*Math.PI/180,150*Math.PI/180,false); ctx.closePath(); ctx.stroke();
當當當當~~~
噗,噴了一口老血,怎麼是一條小船,說好的扇子呢?再看看三角圖形,瞬間就明白了,圖形閉合不是以圓心為起始點的,而是初始弧度為起點,然後閉合的時候是回到初始點,就變成小船了,那怎麼才能畫出一個扇形呢?給個思路,這裡暫時不給代碼,以後有時間當小實例給到大家,如果我以圓心為起點,畫2條直線,連到圓弧的起始點和結束點,是不是就是一個扇形了,哈哈~,不多說了,腦補一下吧,當然,圓弧的起始點的坐標和結束點的坐標計算還是有點費勁的
前面我們畫的是空心的圓或弧,可否畫實心的呢?貌似問的有點多余,上面說了用黑白雙煞,好吧,直接給個一餅好了:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.arc(150,150,50,0,360*Math.PI/180,false); ctx.fill();
咦,怎麼這麼像某島國國旗,還好我用的是默認黑色,噓噓,都沒看到哈~
還有一個方法可以畫圓弧:
arcTo(x1,y1,x2,y2,r) 創建兩個切線之間的弧/曲線
參數:x1,y1 表示第一個坐標,x2,y2表示第二個坐標,r表示曲線半徑
兩個切線之間的曲線,試試:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.moveTo(20,20); ctx.lineTo(100,20); ctx.arcTo(150,20,150,70,50); ctx.lineTo(150,120); ctx.stroke();
果然是要在兩條線段之間寫曲線, 要是先寫2條曲線,在寫arcTo(),貌似就出不來了,這讓我們想到了moveTo(),lineTo(),再寫一個例子:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.moveTo(150, 20); ctx.arcTo(150,200,50,0,20); ctx.stroke();
想試一下,要是只有一條切線,會怎樣?
好大的一個魚鉤啊,看來這樣也是可以的,要是沒有切線,可否?
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.arcTo(150,200,50,0,20); ctx.stroke();
額,狗帶了,沒反應,看來必須至少有一個切線才能畫弧線,有個點都行,要求不算高,滿足你。
感覺這裡始終沒有將清楚,arcTo()為什麼會畫出這樣的曲線呢,我覺得有必要畫一張圖來表示:
它的繪圖原理應該是這樣的,起始點是圓弧的第一個切點,也是畫筆的起始點,然後arcTo的兩個坐標點分別是圓弧的起點和終點,這樣3個點就形成了2天相交的線,然後以半徑為r畫一個圓,與這2條線相切,2個切點就是繪制的這條弧,而第二張圖就是arcTo()所繪制的圖形,為了證實這一點,我們寫一個相近的圖形來看看:
var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.fillRect(100,100,5,5); ctx.fillRect(180,80,5,5); ctx.fillRect(160,180,5,5); ctx.moveTo(62,112); ctx.lineTo(182,82); ctx.lineTo(162,182); //這裡是繪制切線弧 ctx.moveTo(103,103); ctx.arcTo(183,83,162,182,40); ctx.stroke();
對比這2組圖,將生成的弧線用圓對比一下,會發現起點並不是切點,但基本思路是正確的,3點形成一個夾角,然後以r為圓心,畫一個圓,從起點到第二個切點,就是arcTo()方法所繪制的圖形。
今天就到這吧!講的很混亂,東一腳西一腳的,希望你們能懂!最希望的是能對你們有幫助,那就再好不過了!