如何在html5中监听canvas内部元素点击事件?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
像素法
像素检测法的思路是,将canvas中的多个图形(如果有多个的话)分别离屏绘制,并用 getImageData() 方法分别获取到像素数据保存起来。当canvas元素监听到点击事件时,通过点击坐标可以直接推算出点击发生在canvas上的第几个像素,然后遍历前面保存的图形数据,看看这个像素的alpha值是不是0,如果是0说明落点不在当前图形内,否则就说明点到了这个图形。
根据点击坐标得到所点击的像素序号的方法:
像素序号 = (纵坐标-1) * canvas宽度 + 横坐标
比如在宽度为 5 的画布上点击坐标 (3,3) ,根据上述公式得到像素序号是 (3-1) * 5 + 3 = 18 ,如图所示:
因为canvas导出的图形数据是将每个像素以 rgba 的顺序存成4个数字组成的数组,所以想访问指定像素的alpha值,只要读取这个数组的第 pIndex * 4 + 3 个值就可以了,如果这个值不为0,说明该像素可见,也就是点击到了该图形。
这个方法是我认为思路最直接、结果最准确、而且对图形形状没有任何要求的方法,但这个方法有一个致命的局限,当图形需要在画布上移动时,要频繁的创建数据缓存才能保证检测结果准确,受到画布尺寸和图形数量的影响, getImageData() 方法的性能会成为严重的瓶颈。所以如果canvas图形是静态的,这个方法非常适合,否则就不适合用这个方法了。
角度法
角度判断法的原理很容易理解,如果一个点在多边形内部,则该点与多边形所有顶点两两构成的夹角,相加应该刚好等于360°。
计算过程可以转变为以下三个步骤:
1.已知多边形顶点和已知坐标,将坐标与顶点两两组合成三点队列
2. 已知三点求夹角,可以使用 余玄定理
3.判断夹角之和是否360°
每一步都很简单,实现如下:
//计算两点距离 const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) }; //角度法判断点在多边形内部 const checkPointInPolyline = (point, polylinePoints) => { let totalA = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; } else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //计算角度 const angleA = Math.acos((Math.pow(getDistence(A, C), 2) + Math.pow(getDistence(A, B), 2) - Math.pow(getDistence(B, C), 2)) / (2 * getDistence(A, C) * getDistence(A, B))) totalA += angleA } //判断角度之和 return totalA === 2 * Math.PI }
这个方法有一个局限性,就是图形必须是 凸多边形 。如果不是凸多边形需要先切割成凸多边形再计算,这就比较复杂了。
类似的思路还有面积法,如果一个点在多边形内部,那么该点与多边形所有顶点两两构成的三角形,面积相加应该等于多边形的面积,首先计算多边形的面积就很麻烦,所以这种方法可以直接pass掉。
射线法
射线法是一个我讲不清道理但非常好用的方法,只要判断点与多边形一侧的交点个数为奇数,则点在多边形内部。需要注意的是,只要数任何一侧的焦点个数就可以,比如左侧。这个方法不限制多边形的类型,凸多边形、凹多边形甚至环形都可以。
实现起来也非常简单:
const checkPointInPolyline = (point, polylinePoints) => { //射线法 let leftSide = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; } else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //判断左侧相交 let sortByY = [B.y, C.y].sort((a,b) => a-b) if (sortByY[0] < A.y && sortByY[1] > A.y){ if(B.x<A.x || C.x < A.x){ leftSide++ } } } return leftSide % 2 === 1 }
看完上述内容,你们掌握如何在html5中监听canvas内部元素点击事件的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。