關於canvas的事件監聽


對於js一般的事件監聽都是在dom元素的級別上進行的,而canvas內部的元素無法當成dom元素進行那個監聽,也就是說對於瀏覽器,canvas內部有什么元素是根本不關心的。因此要實現canvas內部元素的事件監聽,需要自己實現。

以鼠標事件為例,進行思考:

1.坐標轉換

      首先必須以canvas元素本身的事件監聽為基礎,這個用js的事件監聽即可實現。問題是當dom事件觸發后,我們如何判斷是否觸發了canvas內部元素事件,觸發的是什么事件。

這時需要獲取鼠標事件相對於canvas內的坐標。獲取事件坐標在canvas時間監聽的回調函數中的事件形參event中通過event.clientX和event.clientY獲得,但是這只是相對整個頁面窗口的坐標,需要轉換成相對canvas的坐標。

      canvas對象有一個方法getBoundClientRect(),返回的是canvas元素的邊界框對象,設返回對象為bbox, 此對象的left與top屬性即為canvas左上角點相對窗口的坐標,將事件坐標與canvas坐標相減,得到相對於canvas的坐標。

      然而還有一個問題,canvas內部而言,1像素不一定等於瀏覽器中的1像素,這是因為,canvas作為dom元素有自身的寬高,canvas的內部也有寬高屬性,這兩個大小中有一個縮放關系,導致單位的不統一,之前得到的坐標是相對於

瀏覽器的單位比例而言的,要轉換成canvas的單位比例,將橫縱坐標各乘於(canvas.width / bbox.width)和(canvas.height / bbox.height)即可。

      轉換代碼如下:

1       //傳入canvas對象,與事件坐標參數
var windowToCanvas = function(canvas, x, y){ 2 var bbox; 3 bbox = canvas.getBoundingClientRect(); 4 return { 5 x: (x - bbox.left) * (canvas.width / bbox.width), 6 y: (y - bbox.top) * (canvas.height / bbox.height) 7 }; 8 };

2.監聽器對象

          對鼠標事件的監聽是以坐標范圍為基礎的,一個事件對應一個坐標范圍,若點擊事件的坐標在該范圍內,便出發對應的自定義事件。代碼如下:

 1       var canvasListener = function(canvas){
 2         var func;
 3         this.canvas = canvas;
 4         func = function(obj){
 5           var listener;
 6           listener = obj;
 7           return function(e){
 8             return listener.dealEvents(e);
 9           };
10         };
11         this.canvas.click(func(this));
12         this.events = [];
13       };
//添加自定義事件,參數為坐標范圍(左上角坐標與范圍寬高)和事件回調函數
14 canvasListener.prototype.addEvent = function(x, y, width, height, callback){ 15 var newEvent; 16 newEvent = { 17 x: x, 18 y: y, 19 width: width, 20 height: height, 21 callback: callback 22 }; 23 this.events.push(newEvent); 24 };
//點擊事件觸發時,判斷該觸發哪個自定義事件
25 canvasListener.prototype.dealEvents = function(e){ 26 var loc, i$, ref$, len$, event; 27 loc = windowToCanvas(this.canvas[0], e.clientX, e.clientY); 28 for (i$ = 0, len$ = (ref$ = this.events).length; i$ < len$; ++i$) { 29 event = ref$[i$]; 30 if (loc.x >= event.x && loc.x < event.x + event.width && loc.y >= event.y && loc.y < event.y + event.height) { 31 event.callback(); 32 } 33 } 34 };

 


免責聲明!

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



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