HTML5 快速學習二 Canvas


本篇文章開始講解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

檢測瀏覽器支持情況

我們做兩件事

  1. 我們用一段script判斷瀏覽器支持情況。

    如果不支持可以將提示信息顯示在特定的位置。

    如下圖,我們用了一個id="support"的div來顯示提示升級的信息。

  2. 我們在canvas中寫入一段替代內容.

    如下圖,如果不支持,canvas會顯示替代內容。

瀏覽器支持

把IE調成IE7模式測試下不支持的情況:

 

利用canvas畫一條對角線

對上面的例子做一些修改

在canvas中繪制一條對角線

根據上面的js代碼,歸納出使用canvas API的重要流程

  1. 根據canvas ID值獲取canvas對象訪問權,接着定義一個context變量,調用canvas對象的getContext方法。
  2. 基於這個context執行動作(這里是畫一條對角線)
  3. 通過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),很容易看到這兩種情況的結果是等價的,理解了嗎?

大家體會一下。

我們歸納一下上面的操作:

  1. 根據canvas ID值獲取canvas對象訪問權,接着定義一個context變量,調用canvas對象的getContext方法。
  2. 保存尚未修改的context, 這樣即使進行了繪制和變換操作,也可以恢復到初始狀態(通過后面的restore函數)
  3. 通過translate來移動原點,這個上面已經解釋過了。
  4. 基於移動過的context執行畫線動作
  5. 通過context.stroke()完成線條的繪制。
  6. 最后,恢復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重新繪制新路徑並完全清除之前的所有路徑。

1.繪制樹冠

繪制樹冠的函數

 

為了直觀的顯示圖線的走勢,我畫了個從開始點到頂點的草圖,如下

在canvas上畫樹的函數:

最終結果如下

下面我們對樹冠做一些美化,在stroke之前添加如下代碼

變成了更粗更平滑的棕色線條。

進一步美化,將閉合路徑內部填充為綠色

 

注意,右邊的邊框也變細了。

當我們采用先描邊后填充的方式,會填充一半的邊框。

如果要不填充邊框,需要采用先填充后描邊的方式,如下。

2. 利用fillRect畫樹干(填充矩形區域)

我們先把translate的數值改一下,讓出樹干的位置。

context.translate(130,150);

通過fillRect(x, y, 寬, 高)來畫出樹干。

注意,這段要在context.restore();前面,否則畫的位置就錯了。

最終結果:

Note

fillRect(x,y,width,height)

總結

大家初步可以看到canvas的威力,可以不用借助第三方技術進行繪圖。

當然目前畫的東西還比較簡單,下篇文章將會在這棵樹的基礎上加入其他元素和特殊效果,完成一幅雨水動畫效果的林蔭小道圖。

好了,今天就到這里,歡迎大家多多評論,讓下一篇文章更好:)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM