【第1章 基础知识】1.6 事件处理
文章目录
- 前言
- 一、鼠标事件
- 将鼠标坐标转换为 Canvas 坐标
- 示例-精灵表坐标查看器
- 二、键盘事件
- 三、触摸事件
前言
HTML5 应用程序是以事件来驱动的。可以在 HTML 元素上注册事件监听器,并编写用于响应这些事件的实现代码。几乎所有基于 Canvas 的应用程序都会处理鼠标或触摸事件,还有许多程序也会处理其他各种类型的事件,比如键盘事件或拖放事件。
一、鼠标事件
在 canvas 中检测鼠标事件是非常简单的:可以在 canvas 中增加一个事件监听器,当事件发生时,浏览器就会调用这个监听器。例如:
canvas.onmousedown = function(e) {}
此外,可以使用 addEventListener() 方法来注册监听器:
canvas.addEventListener('mousedown' ,function(e) {})
除了 onmousedown 之外,也可以使用 onmousemove、onmouseup 与 onmouseout 来注册监听器。
使用 onmousedown 这样的方式来注册监听器,比调用 addEventListener() 要稍微简单些。不过,如果要向某个鼠标事件注册许多个监听器的话,那么就得使用 addEventListener() 方法了。
addEventListener()方法允许你在一个元素上注册多个事件监听器,每个监听器都可以独立执行不同的函数。这与传统的on属性(如onclick、onmouseover等)不同,后者每次只能注册一个事件处理函数,如果再次使用on属性注册函数,之前的函数会被覆盖
将鼠标坐标转换为 Canvas 坐标
浏览器通过事件对象传递给监听器的鼠标坐标,是窗口坐标,而不是相对于 canvas 自身的坐标。大部分情况下,开发者需要知道的是发生鼠标事件的点相对于 canvas 的位置,而不是在整个窗口中的位置,所以必须进行坐标转换。转换工作是通过类似下面这样的windowToCanvas() 方法来完成的。
function windowToCanvas(canvas, x, y) {//获取canvas元素的边界框(bouding box)const bbox = canvas.getBoundingClientRect()return {x: x - bbox.left * (canvas.width / bbox.width),y: y - bbox.top * (canvas.height / bbox.height),}
}
示例-精灵表坐标查看器
此示例中,可以通过移动鼠标来观察屏幕中显示的坐标,以此确定精灵表中每张精灵图像的具体位置坐标。当用户移动鼠标时,应用程序会持续地更新精灵表上方的鼠标坐标,同时还会在屏幕上绘制辅助线。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>精灵表坐标查看器Sprite Sheets</title><style>body {background: #dddddd;}#canvas {position: absolute;left: 0px;top: 50px;margin: 20px;background: #ffffff;border: thin inset rgba(100, 150, 230, 0.5);cursor: pointer;}#readout {margin-top: 10px;margin-left: 15px;color: blue;}</style></head><body><!--用来显示当前精灵表坐标--><div id="readout"></div><p>加载一个图片,移动鼠标,获取基于canvas鼠标处精灵表坐标</p><canvas id="canvas" width="500" height="250">Canvas not supported</canvas></body><script>var canvas = document.getElementById('canvas'),context = canvas.getContext('2d'),readout = document.getElementById('readout'),spritesheet = new Image()//Function……/*** 窗口坐标转化为基于Canvas的坐标* @param canvas* @param x* @param y* @returns {{x: number, y: number}}*/function windowToCanvas(canvas, x, y) {//获取canvas元素的边界框(bouding box)var bbox = canvas.getBoundingClientRect()return {x: x - bbox.left * (canvas.width / bbox.width),y: y - bbox.top * (canvas.height / bbox.height),}}/*** 绘制背景条纹线*/function drawBackground() {var VERTICAL_LINE_SOACING = 12,i = context.canvas.heightcontext.clearRect(0, 0, canvas.width, canvas.height)context.strokeStyle = 'lightgray'context.lineWidth = 0.5//预留出顶部4个网格线高的长度供图片占位,从地部划线,从下往上while (i > VERTICAL_LINE_SOACING * 4) {context.beginPath()context.moveTo(0, i)context.lineTo(canvas.width, i)context.stroke()i -= VERTICAL_LINE_SOACING}}/*** 绘制精灵表*/function drawSpritesheet() {//将图片画到画布上context.drawImage(spritesheet, 0, 0)}/*** 绘制光标跟随网格线* @param x* @param y*/function drawGuidelines(x, y) {context.strokeStyle = 'rgba(0,0,230,0.8)'context.lineWidth = 0.5drawVerticalLine(x)drawHorizontalLine(y)}function updateReadout(x, y) {//四舍五入到0位小数并输出到#readout元素中readout.innerHTML = '(' + x.toFixed(0) + ',' + y.toFixed(0) + ')'}/*** 绘制水平跟随线* @param y*/function drawHorizontalLine(y) {context.beginPath()context.moveTo(0, y + 0.5)context.lineTo(context.canvas.width, y + 0.5)context.stroke()}/*** 绘制垂直跟随线* @param x*/function drawVerticalLine(x) {context.beginPath()context.moveTo(x + 0.5, 0)context.lineTo(x + 0.5, context.canvas.height)context.stroke()}//Event handlers……canvas.onmousemove = function (e) {var loc = windowToCanvas(canvas, e.clientX, e.clientY)drawBackground()drawSpritesheet()drawGuidelines(loc.x, loc.y)updateReadout(loc.x, loc.y)}//Initialization//设置图片路径spritesheet.src = 'running-sprite-sheet.png'//加载图片之后画精灵表spritesheet.onload = function (ev) {drawSpritesheet()}//画背景drawBackground()</script>
</html>
二、键盘事件
在浏览器窗口按下某个按键时,浏览器会生成键盘事件。这些事件发生在当前拥有焦点的HTML元素上,如果没有元素拥有焦点,那么事件将会上移至windows和document对象。
一共有三种键盘事件:
- keydown
- keypress
- keyup
canvas 是一个不可获取焦点的元素,所以在 canvas 元素上新增键盘事件监听器是徒劳的。如果想要检测键盘事件的话,你应该在 document 或 window 对象上新增键盘事件监听器,代码如下:
window.addEventListener('keydown', function(e) {},true);
键盘事件常用于文本输入、游戏操作场景中。
三、触摸事件
随着智能手机与平板电脑的出现,HTML 规范也加入了对触摸事件的支持。要了解更多有关触摸事件处理的信息,请参阅本书的第11章。