使用畫布
說了這麽多,什麽是畫布?
Canvas在英文中的意思是“畫布”,但這裏所說的Canvas是HTML5中的新元素,開發者可以在上面繪制壹系列圖形。Canvas簡單地用HTML文件編寫:
& ltcanvas id = " canvas " width = " width " height = " height " > & lt;/canvas & gt;
其中,id屬性可以被所有HTML元素使用,畫布只有最後兩個屬性(分別控制寬度和高度),其他什麽都沒有。至於兼容性,CanIUse表示,目前用戶使用的90%的瀏覽器都支持基本功能,因此大多數情況下可以放心使用。
註意壹定要用畫布自帶的寬度和高度屬性,不要用CSS控制,因為CSS控制會導致畫布變形。可以試著和PhptpShop對比壹下,後者是改變“圖片大小”,前者是正確改變“畫布大小”。比如下圖是三張圖片的橫向拼接:最左邊的黑盒子裏是50px * 50px大小的原圖;中間圖像尺寸改為100px * 100px,圖像變得模糊,但對於圖像本身坐標範圍並沒有放大;最右邊是100px * 100px的正確畫布。
畫布的大部分繪制方法與
我們首先得到這個元素:
var canvas = document . getelementbyid(' canvas ');
然後通過壹個方法得到壹個可以調用所有Canvas API的入口:
var CTX = canvas . get context(' 2d ');
看到2d會興奮的想到3d嗎?沒有3d的寫法,但是想打開3D世界的大門,可以寫canvas.getContext('webgl ')。但WebGL是基於OpenGL ES 2.0的壹套標準,與本文完全不同,這裏就不討論了。
畫布中的基本概念
坐標
與數學中常見的笛卡爾坐標系不同,畫布的坐標系是計算機中常見的坐標系,看起來是這樣的:
畫布左上角為(0,0),隨X向右增加,隨Y減小,且X和Y均為整數(即使在計算過程中不是整數,繪制時也會被視為整數),單位為像素。
起草
帶大家去懷舊。不知道有多少同學小時候玩過logo語言。在裏面,妳可以控制壹只小烏龜在壹塊板上行走、畫畫、寫字、落筆。畫布也是如此。妳需要控制畫筆的移動和繪制。然而,Canvas更高級。可以用壹些函數直接畫,不用控制畫筆的位置。
畫布中的基本圖形
通過上面定義的ctx變量可以做很多有趣的事情。我們先來看看如何畫壹些基本的圖形。
線條
我們指定畫筆移動到某個點,然後告訴畫筆從當前點畫到另壹個點。我們可以讓畫筆多次移動和繪制,最後輸出到屏幕上。例子如下:
ctx.moveTo(10,10);
ctx.lineTo(150,50);
ctx.lineTo(10,50);
ctx.moveTo(10,20);
ctx.lineTo(40,70);
CTX . stroke();
在上面的代碼中,lineTo是壹個用於生成線條的函數。執行後,畫筆移動到行尾。需要註意的是,此時屏幕上不顯示線條,只有調用stroke才會顯示。這種設計是有意義的,因為將內容輸出到屏幕上需要大量的資源。我們可以先存夠線來,最後用筆畫壹個大的。
小路
畫路徑很簡單,先告訴ctx“我要開始畫路徑了”,然後用各種方法(比如lineTo)畫路徑。如果需要畫封閉路徑,最後告訴ctx:“我完成了,妳可以封閉了。”當然,別忘了用stroke輸出到屏幕上。
壹個簡單的例子:
CTX . begin path();
ctx.moveTo(10,10);
ctx.lineTo(150,50);
ctx.lineTo(10,50);
CTX . close path();
CTX . stroke();
如果我不只是畫路徑線,而是想填充整個路徑呢?您可以將最後壹行中的描邊更改為填充,這樣就像在繪圖中使用油漆桶壹樣,閉合路徑中的內容會填充顏色:
CTX . fill();
弧形/圓形
繪制圓弧有許多函數參數:
Ctx.arc(中心x坐標,中心y坐標,半徑,起始角度,終止角度,是否逆時針);
註意在Canvas的坐標系中,角的壹邊是以圓心為圓心向右的水平直線。角度以弧度為單位。比如如下圖所示,確定圓心、起始角(圖中所示的銳角)和終止角(圖中所示的鈍角),方向為逆時針,所以有這樣的圓弧。如果方向是順時針,那將是壹個非常非常大的圓弧與之互補...
所以如果轉2π圈,圓弧就變成圓了,所以畫圓弧也可以畫圓:
CTX . begin path();
Ctx.arc(中心x坐標,中心y坐標,半徑,0,數學。PI * 2,真);
CTX . close path();
最後壹個參數可以隨便填(當然也可以不填),因為2π轉之後就是壹個圓,不管是順時針還是逆時針。
矩形
如果妳只想畫壹個水平和垂直的矩形,妳可以用下面兩種方法:
//僅筆畫
Ctx.strokeRect(左上角X坐標,左上角Y坐標,寬度,高度);
//僅填充
Ctx.fillRect(左上角X坐標,左上角Y坐標,寬度,高度);
線條樣式/填充樣式
之前畫的圖形都是黑色的,但是Canvas絕對不止壹種顏色(不然標準制定者會被噴的很慘)。其實Canvas可以分別設置線條樣式和fillStyle,分別使用strokeStyle和fill style。有三種可能的值:純色、漸變和圖像。既然線條樣式和填充樣式的用法壹樣,我們就以填充樣式為例。如果要設置線條樣式,只需將fillStyle全部改為strokeStyle,裏面的參數不變。
/*純色填充*/
//普通顏色
CTX . fill style = ' # 0000 ff ';
//透明色
ctx.fillStyle = 'rgba(64,0,127,0.5)';
/*漸變填充*/
//設置漸變的大小(參數分別是起點的x和y,終點的x和y)。
var gradient = CTX . createlineargradient(0,0,170,0);
//設置過渡顏色。第壹個參數是漸變的位置,第二個參數是顏色。
gradient.addColorStop(0,' magenta ');
gradient.addColorStop(0.5,'藍色');
gradient . addcolorstop(1.0,'紅色');
//設置填充樣式
ctx.fillStyle = gradient
/*圖片填充*/
//創建圖片
var image =新圖像;
image . src = '/path/to/image . png ';
//創建壹個圖片筆刷筆畫,可以指定圖片的平鋪方式,這裏是水平平鋪。
var pattern = CTX . create pattern(image,' repeat-x ');
//設置筆觸填充
ctx.fillStyle = pattern
關於漸變,除了代碼中提到的線性漸變,還有createRadialGradient,就是徑向漸變。
設置好填充樣式後,就可以用fill來填充了!如果設置了線條樣式,則可以使用描邊到描邊。
當然,對於線條樣式,還有壹個額外的方法叫做lineWidth,可以用來控制線條的寬度。
特性
如果要在畫布上繪制文本,首先需要知道使用的字體和字體大小:
ctx.font = ' 30px Verdana
然後,您可以通過strokeText或fillText來描邊或填充字體。
ctx.strokeText("Hello Coding!", 23, 33);
ctx.fillText("Hello Coding!", 23, 66);
畫
在畫布上畫畫有三種方法:
//指定繪圖位置
ctx.drawImage(image,x,y);
//指定繪圖位置和圖像寬度和高度。
ctx.drawImage(圖像,x,y,寬度,高度);
//指定裁剪區域、繪圖位置和圖像寬度和高度。
ctx.drawImage(image,sx,sy,swidth,she height,x,y,width,height);
這些參數的含義如下:
Image:要使用的圖像、畫布或視頻。
Sx:可選,開始切割的x坐標。
Sy:可選,開始切割的y坐標。
Swidth:可選,裁剪圖像的寬度。
the height:可選,裁剪圖像的高度。
x:放置在畫布上的圖像的x坐標。
放置在畫布上的圖像的Y: Y坐標。
Width:可選,要使用的圖像的寬度。
Height:可選,要使用的圖像的高度。
畫布設置
細心的同學可能會發現,剛才有些屬性直接設置為ctx變量,比如ctx.lineWidth,只要設置了,後面畫的線都是這樣的寬度。
其實畫布的設置有很多,比如我們可以直接移動畫布,旋轉畫布,設置全局繪制透明度等等。這些設置也可以隨時保存和恢復。
有壹點需要註意的是,已經畫在畫布上的東西都已經死了,無論後面做什麽設定都不會改變。這和Windows下的畫圖程序很像。
事不宜遲,只需代碼:
//移動畫布其實就是移動坐標系。
Ctx.translate(向右移動的量,向下移動的量);
//以旋轉中心為坐標系原點旋轉畫布。
Ctx.rotate(順時針旋轉角度);
//圍繞坐標系原點縮放畫布。
Ctx.scale(水平放大,垂直放大);
//設置繪圖透明度,如果fillStyle等屬性設置了透明度,就會疊加。
Ctx.globalAlpha(從零到壹的十進制);
//設置全局組合操作
CTX . globalcompositeoperation = ' lighter ';
//保存當前設置。
CTX . save();
//恢復上次保存的設置。
CTX . restore();
移動、旋轉和縮放實際上是在控制繪圖的坐標系。如果妳在調用這三個方法的時候,腦子裏壹直有壹個校準過的坐標系,效果會很好。
其實畫布的坐標變換遵循的是計算機圖形學的知識:變換矩陣。簡單來說,壹個坐標可以看成壹個矩陣,坐標的變換可以通過坐標對應的矩陣乘以變換矩陣來實現。為了提高計算效率,我們可以先計算幾個變換合並後的變換矩陣,然後直接通過transform函數對當前坐標系進行變換,或者在變換前通過setTransform函數將坐標系重置為初始狀態。至於變換矩陣的內容,對於本文來說有點超綱。
全局組合操作有點像PhotoShop中的“混合選項”,具體實現方式還沒有完全確定。目前常見的瀏覽器有統壹的實現方法:source-over、source-top、destination-over、destination-out、lighter和xor。具體的行為可以在Mozilla的官方文檔中找到,但是由於標準還沒有完全確定,其他瀏覽器並不保證所有的行為都符合Mozilla的標準。壹般來說,source-over和lighter是兩個常見的標準,這兩個標準在瀏覽器界是無可爭議的。
至於保存和恢復設置,就有點好玩了。首先妳要知道壹個叫“棧”的東西。
Stack是壹維數組,只能單向操作。棧開始是空的,所以我們可以從這個方向把元素推入數組,從這個方向只彈出最後壹個元素(棧頂元素),沒有額外的操作。當然,pop的次數不能多於push的次數,因為當POP到達棧底時,棧中已經沒有元素了,這個時候再POP就沒有意義了。Stack有很多用途,比如括號匹配、表達式求值、深度優先搜索,甚至大部分語言的函數調用都使用stack。
我們每次調用save函數,實際上都是把當前的全局設置推到壹個特殊的棧上,每次調用restore函數,都是把最後保存的內容彈出來,用它來覆蓋當前的全局設置,這樣棧頂就是最後保存的內容。保存和恢復在某些情況下非常有用,比如我需要畫壹個歪圖,然後繼續畫壹個直圖,這樣我可以先調用save,然後調用rotate,畫完圖再恢復,繼續畫其他圖。
其實canvas的方法有很多,比如toDataURL直接把當前canvas內容轉換成十六進制數據-url,getImageData直接把圖像轉換成RGBA數組用於圖像處理算法,putImageData把RGBA數組轉換成圖片顯示在Canvas上等等。如果伴隨著JavaScript的定期更新(最好使用requestAnimationFrame而不是setInterval),可以產生動畫效果。網上也有很多Canvas的庫,可以方便程序員基於Canvas編寫自己的特效或者函數。在這裏我想說壹句話:畫布的能力和每個人的腦洞大小壹樣強~