糯米文學吧

位置:首頁 > 設計 > 網頁設計

HTML5中Canvas的事件處理介紹

DOM是Web前端領域非常重要的組成部分,不僅在處理HTML元素時會用到DOM,圖形編程也同樣會用到。比如SVG繪圖,各種圖形都是以DOM節點的形式插入到頁面中,這就意味着可以使用DOM方法對圖形進行操作。比如有一個 元素,可以直接用jquery增加click事件$('#p1')k(function(){…})"。然而這種DOM處理方法在HTML5的Canvas裏不再適用,Canvas使用的是另外一套機制,無論在Canvas上繪製多少圖形,Canvas都是一個整體,圖形本身實際都是Canvas的一部分,不可單獨獲取,所以也就無法直接給某個圖形增加JavaScript事件。

HTML5中Canvas的事件處理介紹

  Canvas的限制

在Canvas裏,所有圖形都繪製在幀上,繪製方法不會將繪製好的圖形元素作為一個返回值輸出,js也無法獲取到已經繪製好的圖形元素。比如:

代碼如下:

cvs = lementById('mycanvas');

ctx = ontext('2d');

theRect = (10, 10, 100, 100);

ke();

(theRect); //undefined

這段代碼在canvas標籤裏繪製了一個矩形,首先可以看到繪製圖形的rect方法沒有返回值。如果打開瀏覽器的開發者工具,還可以看到canvas標籤內部沒有增加任何內容,而在js裏獲取到的canvas元素以及當前的上下文,也都沒有任何表示新增圖形的內容。

所以,前端常用的dom方法在canvas裏是不適用的。比如點擊上面Canvas裏的矩形,實際點擊的是整個Canvas元素。

  給Canvas元素綁定事件

由於事件只能達到Canvas元素這一層,所以,如果想進一步深入,識別點擊發生在Canvas內部的哪一個圖形上,就需要增加代碼來進行處理。基本思路是:給Canvas元素綁定事件,當事件發生時,檢查事件對象的位置,然後檢查哪些圖形覆蓋了該位置。比如上面的例子裏畫過一個矩形,該矩形覆蓋x軸10-110、y軸10-110的範圍。只要鼠標點擊在這個範圍裏,就可以視為點擊了該矩形,也就可以手動觸發矩形需要處理的點擊事件。思路其實比較簡單,但是實現起來還是稍微有點複雜。不僅要考慮這個判斷過程的效率,有些地方還需要重新判斷事件類型,設置要重新定義一個Canvas內部的捕獲和冒泡機制。

首先要做的,是給Canvas元素綁定事件,比如Canvas內部某個圖形要綁定點擊事件,就需要通過Canvas元素代理該事件:

  代碼如下:

cvs = lementById('mycanvas');

ventListener('click', function(e){

//...

}, false);

接下來需要判斷事件對象發生的位置,事件對象e的layerX和layerY屬性表示Canvas內部座標系中的座標。但是這個屬性Opera不支持,Safari也打算移除,所以要做一些兼容寫法:

代碼如下:

function getEventPosition(ev){

var x, y;

if (rX || rX == 0) {

x = rX;

y = rY;

} else if (etX || etX == 0) { // Opera

x = etX;

y = etY;

}

return {x: x, y: y};

}

//注:使用上面這個函數,需要給Canvas元素的position設為absolute。

現在有了事件對象的座標位置,下面就要判斷Canvas裏的圖形,有哪些覆蓋了這個座標。

isPointInPath方法

Canvas的isPointInPath方法可以判斷當前上下文的圖形是否覆蓋了某個座標,比如:

代碼如下:

cvs = lementById('mycanvas');

ctx = ontext('2d');

(10, 10, 100, 100);

ke();

intInPath(50, 50); //true

intInPath(5, 5); //false

接下來增加一個事件判斷,就可以判斷一個點擊事件是否發生在矩形上:

代碼如下:

ventListener('click', function(e){

p = getEventPosition(e);

if(intInPath(p.x, p.y)){

//點擊了矩形

}

}, false);

以上就是處理Canvas事件的基本方法,但是上面的代碼還有侷限,由於isPointInPath方法僅判斷當前上下文環境中的路徑,所以當Canvas裏已經繪製了多個圖形時,僅能以最後一個圖形的上下文環境來判斷事件,比如:

代碼如下: