第一章 基础知识

第六节 事件处理

    HTML5应用程序是以事件来驱动的。可以在HTML元素上注册事件监听器,并编写用于响应这些事件的实现代码。几乎所有基于Canvas的应用程序都会处理鼠标或触摸事件,有些程序则两种事件都会处理,还有许多程序也会处理其他各种类型的事件,比如键盘事件或者拖放事件。

    1.6.1 鼠标事件

    在canvas中检测鼠标事件是非常简单的:可以在canvas中增加一个事件监听器,当事件发生时,浏览器就会调用这个监听器了。举例来说,要监听“按下鼠标事件”,你可以这样做:

    canvas.onmousedown = function (e) {

        // React to the mouse down event

    };

    此外,可以使用更为通用的addEventListener()方法来注册监听器:

    canvas.addEventListener('mousedown', function (e){

        // React to the mouse down event

    });

    除了onmousedown之外,也可以使用onmousemove、onmouseup与onmouseout来注册监听器。

    使用onmousedown、onmousemove这样的方式来注册监听器,比调用addEventListener()要稍微简单些,不过,如果要向某个鼠标事件注册许多个监听器的话,那么就得使用addEventListener()方法了。

    将鼠标坐标转换为Canvas坐标

    浏览器通过事件对象传递给监听器的鼠标坐标,是窗口坐标(window coordinate),而不是相对与canvas自身的坐标。

    大部分情况下,开发者需要知道的是发生鼠标事件的点相对于canvas的位置,而不是在整个窗口中的位置,所以必须进行坐标转换。举例来说,在图1-14中,canvas上面显示了一幅精灵表(sprite sheet)的图像。精灵表指的是一张包含许多动画图像的图片。在动画的播放过程中,每次都要在精灵表中选取一张图像显示出来,这意味着你必须知道精灵表中每张图像的精确坐标。

精灵表坐标查看器

图1-14 精灵表坐标查看器

    借助图1-14中所示的应用程序,可以通过移动鼠标来观察屏幕中显示的坐标,以此确定精灵表中每张精灵图像的具体位置坐标。当用户移动鼠标时,应用程序会持续地更新精灵表上方的鼠标坐标,同时还会在屏幕上绘制辅助线。

    该应用程序向canvas注册了一个mousemove事件监听器,然后,等到浏览器回调这个监听器时,应用程序会将相对与窗口的鼠标坐标转换为canvas坐标。转换工作是通过类似下面这样的windowToCanvas()方法来完成的:

    function windowToCanvas(canvas, x, y) {

       var bbox = canvas.getBoundingClientRect();

    return { x: x - bbox.left * (canvas.width  /bbox.width),

            y: y - bbox.top  * (canvas.height /bbox.height)

          };
    }

    canvas.onmousemove = function (e) {

       var loc = windowToCanvas(canvas, e.clientX,e.clientY);

       drawBackground();

       drawSpritesheet();

       drawGuidelines(loc.x, loc.y);

       updateReadout(loc.x, loc.y);

    };

    ...

    上述windowToCanvas()方法在canvas对象上调用getBoundingClientRect()方法,来获取canvas元素的边界框(bounding box),该边界框的坐标是相对于整个窗口的。然后,windowToCanvas()方法返回了一个对象,其x与y属性分别对应于鼠标在canvas之中的坐标。

    请注意,windowToCanvas()方法不只是将canvas边界框的x、y坐标从窗口坐标中减去,而且在canvas元素大小与绘图表面大小不相符时,它还对这两个坐标进行了缩放。请参阅本书1.1.1小节,该小节解释了canvas元素大小与canvas绘图表面大小的区别。

    图1-14中所示应用程序的HTML代码列在了程序清单1-5之中,其JavaScript代码列在了程序清单1-6之中。