本篇文章開始講解HTML5的核心功能之一:Canvas
通過Canvas可以動態生成和展示圖形、圖表、影象以及動畫。
Canvas API功能非常多,我們將討論最常用的功能。
我們先新建一個canvas看看。
我們給canvas加一個邊框,這樣比較方便看。
可以看到, canvas會建立一塊矩形區域,預設情況下生成大小是300*150畫素。
在頁面中加入canvas後,我們便可以通過js來自由地控制她。
例如 新增圖片、線條以及文字,也可以在裡面繪圖,甚至加入高階動畫。
Note
把canvas當作一個普通的標籤,可以通過應用CSS的方式來改變樣式,而且一些CSS屬性還可以被canvas內的元素繼承。
例如字型樣式,在canvas內新增文字,其樣式預設是同canvas元素本身是一樣的。
文章提綱
-
要點
-
理論基礎/前置條件
-
詳細步驟
-
總結
要點
掌握使用canvas API的重要流程
掌握常用的canvas API:例如moveTo, lineTo, beginPath, closePath,stroke,fill等
充分理解例子
理論基礎 -- canvas座標
如下圖,canvas中的座標是從左上角開始,x軸沿著水平方向(按畫素)向右延伸,y軸沿垂直方向向下延伸。
最左上角座標為 (0,0) 的點為原點。
詳細步驟 -- 使用HTML5 canvas API
檢測瀏覽器支援情況
我們做兩件事
-
我們用一段script判斷瀏覽器支援情況。
如果不支援可以將提示資訊顯示在特定的位置。
如下圖,我們用了一個id="support"的div來顯示提示升級的資訊。
-
我們在canvas中寫入一段替代內容.
如下圖,如果不支援,canvas會顯示替代內容。
瀏覽器支援
把IE調成IE7模式測試下不支援的情況:
利用canvas畫一條對角線
對上面的例子做一些修改
在canvas中繪製一條對角線
根據上面的js程式碼,歸納出使用canvas API的重要流程。
-
根據canvas ID值獲取canvas物件訪問權,接著定義一個context變數,呼叫canvas物件的getContext方法。
-
基於這個context執行動作(這裡是畫一條對角線)
-
通過context.stroke()完成線條的繪製。
Note
這裡有一個坑。我原來將設定canvas長寬放在了style裡面。如下圖。
出現問題的原因:
canvas的width和height是畫布的實際寬度和高度,繪製的圖形在這個畫布上面。
canvas的style的width和height是canvas在瀏覽器中被渲染的高度和寬度。
因此需要注意設定寬度時要在外面設定。
使用變換(transformation)畫對角線
下面來看canvas上繪製影象的另外一種方式:使用變換(transformation)。
transformation是實現複雜canvas操作的最好方式(就單個上面繪製對角線來說看起來是更加複雜了點)
理解 變換(transformation):
把它當成是介於開發人員發出的指令和canvas顯示結果之間的一個修正層 (modification layer)
注意 不管在開發中是否使用變換,修正層始終存在。
每個繪製操作的結果顯示在canvas上之前都要經過修正層去修正。
雖然這麼做增加了額外的複雜性,但卻為繪製系統新增了更為強大的功能。
Note
不在程式碼中呼叫變換函式並不意味著可以提升canvas的效能。
canvas在執行的時候,變換會被呈現引擎隱式呼叫,這與開發人員是否直接呼叫無關。
可重用程式碼的一條重要建議:
一般繪製都應從原點開始,應用變換(縮放,平移,旋轉等),然後不斷修改程式碼直至達到希望的效果。
示例
這個程式碼的結果和上面是一模一樣的。
大家注意這兩種程式碼的差別:
對第二種方式, translate(70,140) 代表將原點移到 (70,140) 這個位置。
也就是說,接下來所有操作都是相對於 (70,140) 這個位置來操作的。
第一種情況是(70,140)à(140,70),
第二種情況是(0,0)à(70,140)à(70,-70)
第二種情況的(70, -70)是相對於新的原點(70,140)點來說的,相對於一開始的原點座標是(70+70,-70+140),很容易看到這兩種情況的結果是等價的,理解了嗎?
大家體會一下。
我們歸納一下上面的操作:
-
根據canvas ID值獲取canvas物件訪問權,接著定義一個context變數,呼叫canvas物件的getContext方法。
-
儲存尚未修改的context, 這樣即使進行了繪製和變換操作,也可以恢復到初始狀態(通過後面的restore函式)
-
通過translate來移動原點,這個上面已經解釋過了。
-
基於移動過的context執行畫線動作
-
通過context.stroke()完成線條的繪製。
-
最後,恢復context至原始狀態,這樣後續的canvas操作就不會被剛才的平移操作影響了。
畫樹
現在學習稍微複雜點的圖形。
前面繪製的一條對角線算是一條簡單路徑。
實際上路徑可以很複雜:多條線、曲線段、甚至是子路徑。
如果想在canvas上繪製任意形狀,那麼你需要重點關注路徑API
按照慣例,不論開始繪製何種圖形,第一個需要呼叫的就是beginPath, 對於canvas來說,beginPath函式的最大用處是canvas需要據此來計算圖形的內部和外部範圍,以便完成後續的描邊和填充。
路徑會跟蹤當前座標,預設值是原點。
呼叫beginPath之後,就可以使用context的各種方法來繪製想要的形狀了。
到目前為止已經使用了幾個簡單的context路徑函式。
moveTo(x,y)
lineTo(x,y)
上面兩個函式的區別是:moveTo就像是提起畫筆,移動到新位置;
而lineTo告訴canvas用畫筆從紙上的舊座標畫條直線到新座標。
注意,不管呼叫的是哪一個,都不會真正畫出圖形,因為我們還沒有呼叫stroke或者fill函式。
目前我們只是定義路徑的位置,以便後面繪製時使用。
另外再介紹一個路徑函式closePath, 這個函式和lineTo很像,唯一的差別是會將路徑的起始座標 自動作為 目標座標。
clothPath還會通知canvas當前繪製的圖形已經完全閉合或者形成了完全封閉的區域,這對將來的填充和描邊都非常有用。
此時,可以在已有的路徑中繼續建立其他的子路徑,或者隨時呼叫beginPath重新繪製新路徑並完全清除之前的所有路徑。
繪製樹冠的函式
為了直觀的顯示圖線的走勢,我畫了個從開始點到頂點的草圖,如下
在canvas上畫樹的函式:
最終結果如下
下面我們對樹冠做一些美化,在stroke之前新增如下程式碼
變成了更粗更平滑的棕色線條。
進一步美化,將閉合路徑內部填充為綠色。
注意,右邊的邊框也變細了。
當我們採用先描邊後填充的方式,會填充一半的邊框。
如果要不填充邊框,需要採用先填充後描邊的方式,如下。
2. 利用fillRect畫樹幹(填充矩形區域)
我們先把translate的數值改一下,讓出樹幹的位置。
context.translate(130,150);
通過fillRect(x, y, 寬, 高)來畫出樹幹。
注意,這段要在context.restore();前面,否則畫的位置就錯了。
最終結果:
Note
fillRect(x,y,width,height)
總結
大家初步可以看到canvas的威力,可以不用藉助第三方技術進行繪圖。
當然目前畫的東西還比較簡單,下篇文章將會在這棵樹的基礎上加入其他元素和特殊效果,完成一幅雨水動畫效果的林蔭小道圖。
好了,今天就到這裡,歡迎大家多多評論,讓下一篇文章更好:)