當前位置:成語大全網 - 詩歌朗誦 - 如何用畫布畫出各種圖形

如何用畫布畫出各種圖形

HTML5的標準已經出來很久了,但是好像現在很多地方都不用裏面的畫布了。壹個很重要的原因是畫布的標準還沒有完全確定,不適合在生產環境下大規模使用。不過帆布的優勢也很明顯。比如在繪制包含大量元素的圖表時,SVG往往會因為性能問題而力不從心。比如我看過的壹個技術分享會的抽獎環節,雖然效果很炫,但是因為每個頭像都是DOM,CSS3控制的動畫導致性能很低。另外,隨著硬件性能的提高,視頻拍攝、圖像處理等功能也可以逐步在網頁上實現。大部分網站都使用Flash,但是Flash在Mac電腦上的性能並不高,還需要壹些額外的知識。Canvas使用JavaScript直接繪制,對Mac比較友好,可以算是Flash的繼承者。

使用畫布

說了這麽多,什麽是畫布?

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編寫自己的特效或者函數。在這裏我想說壹句話:畫布的能力和每個人的腦洞大小壹樣強~