HTML5 Canvas的事件处置介绍
DOM是Web前端领域非常重要的组成部分,不仅在处置HTML元素时会用到DOM,图形编程也一样会用到。比方SVG画图,各种图形都是以DOM节点的情势插入到页面中,这就意味着可以使用DOM办法对图形停止操纵。比方有一个<path id="p1">元素,可以直接用jquery增添click事件$('#p1').click(function(){…})"。然而这种DOM处置办法在HTML5的Canvas里不再适用,Canvas使用的是别的一套机制,不管在Canvas上绘制多少图形,Canvas都是一个团体,图形本身实际都是Canvas的一部分,不成独自猎取,所以也就没法直接给某个图形增添JavaScript事件。
Canvas的限制
在Canvas里,所有图形都绘制在帧上,绘制办法不会将绘制好的图形元素作为一个返回值输出,js也没法猎取到已经绘制好的图形元素。比方:
复制代码
代码如下:
cvs = document.getElementById('mycanvas'); ctx = canvas.getContext('2d'); theRect = ctx.rect(10, 10, 100, 100); ctx.stroke(); console.log(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 = document.getElementById('mycanvas'); cvs.addEventListener('click', function(e){ //... }, false);
接下来需要推断事件对象发生的位置,事件对象e的layerX和layerY属性表示Canvas内部坐标系中的坐标。但是这个属性Opera不支撑,Safari也打算移除,所以要做一些兼容写法:
复制代码
代码如下:
function getEventPosition(ev){ var x, y; if (ev.layerX || ev.layerX == 0) { x = ev.layerX; y = ev.layerY; } else if (ev.offsetX || ev.offsetX == 0) { // Opera x = ev.offsetX; y = ev.offsetY; } return {x: x, y: y}; }
//注:使用上面这个函数,需要给Canvas元素的position设为absolute。
此刻有了事件对象的坐标位置,下面就要推断Canvas里的图形,是什么覆盖了这个坐标。
isPointInPath办法
Canvas的isPointInPath办法可以推断当前上下文的图形可否覆盖了某个坐标,比方:
复制代码
代码如下:
cvs = document.getElementById('mycanvas'); ctx = canvas.getContext('2d'); ctx.rect(10, 10, 100, 100); ctx.stroke(); ctx.isPointInPath(50, 50); //true ctx.isPointInPath(5, 5); //false
接下来增添一个事件推断,就可以推断一个点击事件可否发生在矩形上:
复制代码
代码如下:
cvs.addEventListener('click', function(e){ p = getEventPosition(e); if(ctx.isPointInPath(p.x, p.y)){ //点击了矩形 } }, false);
以上就是处置Canvas事件的根本办法,但是上面的代码还有局限,由于isPointInPath办法仅推断当前上下文环境中的途径,所以当Canvas里已经绘制了多个图形时,仅能以最后一个图形的上下文环境来推断事件,比方:
复制代码
代码如下:
cvs = document.getElementById('mycanvas'); ctx = canvas.getContext('2d'); ctx.beginPath(); ctx.rect(10, 10, 100, 100); ctx.stroke(); ctx.isPointInPath(20, 20); //true ctx.beginPath(); ctx.rect(110, 110, 100, 100); ctx.stroke(); ctx.isPointInPath(150, 150); //true ctx.isPointInPath(20, 20); //false
从上面这段代码可以看到,isPointInPath办法仅能识别当前上下文环境里的图形途径,而此前绘制的途径,没法回溯推断。这种问题的解决办法是:当点击事件发生时,重绘所有图形,每绘制一个就使用isPointInPath办法,推断事件坐标可否在该图形覆盖范畴内。
轮回重绘和事件冒泡
为了实现轮回重绘,所以就要将图形的根本参数事先留存下来:
复制代码
代码如下:
arr = [ {x:10, y:10, width:100, height:100}, {x:110, y:110, width:100, height:100} ]; cvs = document.getElementById('mycanvas'); ctx = canvas.getContext('2d'); draw(); function draw(){ ctx.clearRech(0, 0, cvs.width, cvs.height); arr.forEach(function(v){ ctx.beginPath(); ctx.rect(v.x, v.y, v.width, v.height); ctx.stroke(); }); }
上面的代码事先将两个矩形的根本参数留存下来,每次调取draw办法,就会轮回调取这些根本参数,用于绘制两个矩形。这里还使用了clearRect办法,用于在重绘时清空画布。接下来要做的是增添事件代理,乃至在重绘时对每一个上下文环境使用isPointInPath办法:
复制代码
代码如下:
cvs.addEventListener('click', function(e){ p = getEventPosition(e); draw(p); }, false);
事件发生时,将事件对象的坐标传给draw办法处置。这里还需要对draw办法做一些小改动:
复制代码
代码如下:
function draw(p){ var who = []; ctx.clearRech(0, 0, cvs.width, cvs.height); arr.forEach(function(v, i){ ctx.beginPath(); ctx.rect(v.x, v.y, v.width, v.height); ctx.stroke(); if(p && ctx.isPointInPath(p.x, p.y)){ //假如传入了事件坐标,就用isPointInPath推断一下 //假如当前环境覆盖了该坐标,就将当前环境的index值放到数组里 who.push(i); } }); //按照数组中的index值,可以到arr数组中寻到响应的元素。 return who; }
在上面代码中,点击事件发生时draw办法会施行一次重绘,并在重绘历程中检查每一个图形可否覆盖了事件坐标,假如推断为真,则视为点击了该图形,并将该图形的index值放入数组,最后将数组作为draw办法的返回值。在这种处置机制下,假如Canvas里有N个图形,它们有一部分是重叠的,而点击事件刚巧发生在这个重叠区域上,那么draw办法的返回数组里会有N个成员。这时就有点相似事件冒泡的状况,数组的最后一个成员处于Canvas最上层,而第一个成员则在最基层,我们可以视为最上层的成员是e.target,而其他成员则是冒泡历程中传递到的节点。当然这只是最简便的一种处置办法,假如真要模拟DOM处置,还要给图形设定父子级关系。
以上就是Canvas事件处置的根本办法。在实际使用时,怎样缓存图形参数,怎样停止轮回重绘,乃至怎样处置事件冒泡,都还需要按照实际状况花一些心思去处置。别的,click是一个比力好处置的事件,相对费事的是mou搜索引擎优化ver、mou搜索引擎优化ut和mousemove这些事件,由于鼠标一旦进入Canvas元素,始终发生的都是mousemove事件,所以假如要给某个图形独自设定mou搜索引擎优化ver或mou搜索引擎优化ut,还需要记载鼠标移动的道路,给图形设定进出状态。由于处置的步骤变得复杂起来,必需对机能问题提高关注。
以上就是HTML5 Canvas的事件处置介绍的具体内容,更多请关注百分百源码网其它相关文章!