使用者互動也許是我們學習canvas動畫中首先需要掌握的部分。畢竟,如果沒有互動或者向動畫中做一些動態的輸入,那麼這跟看電影有什麼區別呢?使用者互動基於事件,一般來說包括:滑鼠事件
,觸控事件
和鍵盤事件
。
1、事件和事件執行
在理解事件之前,你需要明白什麼是listener
和handler
。
listener(即監聽器)決定當一個事件發生時是否做出反應。handler(即執行者)是一個函式,當事件發生時被呼叫。好了,扯了這麼多直接上程式碼:
element.addEventListener(type, handler[, useCapture]);
type: 事件型別
handler: 事件執行函式
useCapture: 可選,為布林值false/true, 表示在冒泡/捕獲階段執行
通過方法addEventListener
來為某一元素新增事件,具體到我們的canvas上是什麼樣的呢?加入我們現在想要在canvas上繫結一個mousedown
事件,具體程式碼如下:
canvas.addEventListener(`mousedown`, function(event){
console.log("Mouse pressed on element");
}, false)
這樣我們就為canvas繫結了滑鼠點選事件,當在canvas上按下滑鼠是就會在控制檯看到列印出 “Mouse pressed on element”。
那麼既然有新增事件(addEventListener
),就有移除事件(removeEventListener
),使用方式與新增事件幾乎完全一樣:
element.removeEventListener(type, handler[, useCapture]);
type: 事件型別
handler: 事件執行函式
useCapture: 可選,為布林值false/true, 表示在冒泡/捕獲階段執行
唯一需要注意的是handler
,即移除事件的函式,這裡只能寫函式名,而不能像新增事件一樣將整個功能函式全部寫入。也就是說,在新增某個事件的時候,我們可以將需要執行的函式寫在事件監聽之外並命名,這樣如果你想要在後續的程式碼中移除該事件,直接將函式名傳入移除事件的handler
中即可。
現在讓我們來實驗下先為canvas新增一個事件,再將其移除
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script></script>
<script>
window.onload = function(){
var canvas = document.getElementById(`canvas`);
//定義的執行函式add
function add(event){
console.log("mouse down");
}
canvas.addEventListener(`mousedown`, add, false);
//移除事件mousedown
canvas.removeEventListener(`mousedown`, add, false)
}
</script>
</body>
現在你可以看看控制檯是否還能列印出“mouse down”!
2.滑鼠事件
滑鼠事件一共可以分為:
-
mousedown
-
mouseup
-
click
-
dbclick
-
mousewheel
-
mouseover
-
mouseout
每一個滑鼠事件都包含兩個屬性來決定當前滑鼠的位置:pageX
和pageY
。通過pageX
和pageY
,還有canvas元素的偏移位置,我們就能夠計算出滑鼠具體是在canvas元素的什麼位置。為了考慮不同瀏覽器的相容性,以防萬一你可以使用clientX
和clientY
。在這裡,我們建立一個js檔案,名為**utils.js**
,這個檔案是我們的一個工具函式,裡面會逐漸加入一些我們重複使用的方法,那麼現在我們向我們的工具函式中新增第一個方法captureMouse
,具體程式碼如下:
utils.js檔案
//將utils定義為window物件下的一個屬性,屬性值為物件
window.utils = {};
//在utils物件上定義捕獲座標的方法
window.utils.captureMouse = function(element){
//定義一個名為mouse的物件
var mouse = {x:0,y:0};
//為元素繫結mousemove事件
element.addEventListener(`mousemove`,function(event){
var x,y;
//獲取滑鼠位於當前螢幕的位置, 並作相容處理
if(event.pageX||event.pageY){
x = event.pageX;
y = event.pageY;
}else{
x = event.clientX + document.body.scrollLeft +document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop +document.documentElement.scrollTop;
}
//將當前的座標值減去元素的偏移位置,即為滑鼠位於當前canvas的位置
x -= element.offsetLeft;
y -= element.offsetTop;
mouse.x = x;
mouse.y = y;
},false);
//返回值為mouse物件
return mouse;
}
這個方法將DOM元素作為引數傳入,這樣我們只要將canvas傳入就可以獲取到滑鼠在當前canvas的位置。具體程式碼如下:
<canvas id="canvas" width=`500` height="500" style="background:#000">
<p>you browser not support canvas!<p>
</canvas>
<script src=`../js/utils.js`></script>
<script>
window.onload = function(){
var canvas = document.getElementById(`canvas`),
//將canvas傳入,該方法會返回一個包含屬性x和y的物件
mouse = utils.captureMouse(canvas);
//為canvas繫結mousedown事件,當滑鼠按下的時候列印出當前滑鼠相對於canvas的座標值
canvas.addEventListener(`mousedown`,function(event){
console.log("x:" +mouse.x +",y:" + mouse.y);
});
</script>
Have a try!!!看看能否成功。
getBoundingClientRect()
其實,關於canvas的滑鼠位置獲取的方法還可以應用它自身的一個方法getBoundingClientRect
,這裡做一個介紹,你可以使用,但本系列文章主要使用上面這種更具廣泛性的方法。具體程式碼可以參考如下:
canvas.addEventListener(`mousedown`,function(event){
//event相容處理
var event = event || window.event;
//相容處理,獲取當前滑鼠相對螢幕的座標
var winX = event.clientX+document.body.scrollLeft +document.documentElement.scrollLeft || event.pageX;
var winY = event.clientY+document.body.scrollTop +document.documentElement.scrollTop || event.pageY;
//定義一個物件
var can = {x:0, y:0};
//呼叫getBoundingClientRect方法,該方法返回一個物件,包含canvas的left、 top、 width、 height等值
var canBox = canvas.getBoundingClientRect();
//(winX - canBox.left):與上面的含義一樣,是減去canvas的偏移量
//(canvas.width/canBox.width):一般來說canvas.width和canBox.width是一樣的,也就是說這兩個的比值為1.但不排除你會為canvas設定邊框,這是實際的座標位置就會有所變化,比如canvas.width = 500, 你可能設定了一個1px的邊框,那麼canBox.width = 502, 所以比值就不為1了。這樣做只是讓資料更精確。
can.x = (winX - canBox.left)*(canvas.width/canBox.width);
can.y = (winY - canBox.top)*(canvas.height/canBox.height);
//輸出
console.log(can.x,can.y);
},false);
3、鍵盤事件
鍵盤事件就兩個:
-
keydown
-
keyup
我們同樣可以向繫結滑鼠事件那樣為canvas繫結鍵盤事件。好吧!現在我們來看看,如何將一個鍵盤事件繫結到window(為什麼不直接繫結到canvas上呢?想想)上:
<body >
<p>任意按下按鍵</p>
<script>
window.onload = function(){
//定義鍵盤事件
function onKeyboard(event){
switch (event.keyCode){
case 38:
console.log(`up!`);
break;
case 40:
console.log(`down!`);
break;
case 37:
console.log(`left!`);
break;
case 39:
console.log(`right!`);
break;
default:
console.log(event.keyCode);
}
}
//為window物件繫結鍵盤事件
window.addEventListener(`keydown`,onKeyboard,false);
}
</script>
</body>
試一試,當按下滑鼠的方向鍵是是否在控制檯列印出了相應的資訊!
4、觸控事件
觸控事件包括以下3種:
-
touchstart
-
touchend
-
touchmove
觸控實踐中,手指就充當了滑鼠的作用。同樣我們最為關心的是當前觸控的位置。和captureMouse
方法一樣,這裡在我們的工具函式檔案中,需要新增一新的方法來捕獲觸控的位置,名為captureTouch
,現在在utils.js檔案中新增如下方法:
utils.js檔案
window.utils.captureTouch = function (element) {
var touch = {
x: null,
y: null,
isPressed: false,
event: null
};
var body_scrollLeft = document.body.scrollLeft,
element_scrollLeft = document.documentElement.scrollLeft,
body_scrollTop = document.body.scrollTop,
element_scrollTop = document.documentElement.scrollTop,
offsetLeft = element.offsetLeft,
offsetTop = element.offsetTop;
// 繫結touchstart事件
element.addEventListener(`touchstart`, function (event) {
touch.isPressed = true;
touch.event = event;
}, false);
// 繫結touchend事件
element.addEventListener(`touchend`, function (event) {
touch.isPressed = false;
touch.x = null;
touch.y = null;
touch.event = event;
}, false);
//繫結touchmove事件
element.addEventListener(`touchmove`, function (event) {
var x, y,
touch_event = event.touches[0]; //第一次touch
if (touch_event.pageX || touch_event.pageY) {
x = touch_event.pageX;
y = touch_event.pageY;
} else {
x = touch_event.clientX + body_scrollLeft + element_scrollLeft;
y = touch_event.clientY + body_scrollTop + element_scrollTop;
}
//剪去偏移量
x -= offsetLeft;
y -= offsetTop;
touch.x = x;
touch.y = y;
touch.event = event;
}, false);
//返回touch物件
return touch;
};
總結
這一節主要介紹使用者與canvas互動的各種事件,重要的是你應該在你自己的工具函式檔案中包含了以下兩個方法:utils.captureTouch
和utils.captureMouse
這兩個方法都是為了獲取當前相對於canvas元素的位置。我們將在後面的章節中頻繁使用。當然,除了這兩個方法,由於我們使用的requestAnimationFrame
方法同樣也涉及到相容性的問題,我們將它一同新增到utils.js
中,具體程式碼請檢視utils.js
檔案。
下一節,三角函式座標旋轉敬請期待!!!