加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

html5中监听canvas内部元素点击事件的三种方法

发布时间:2020-03-29 11:24:52 所属栏目:编程 来源:站长网
导读:canvas内部元素不能像DOM元素一样利便的添加交互变乱监听,由于canvas内不存在元素这个观念,他们仅仅是canvas绘制出来的图形。这对付交互开拓来说是一个必经障碍,想要监听图形的点击变乱思绪很简朴,只要监听canvas元素自己的点击变乱,再判定点击坐标位

canvas内部元素不能像DOM元素一样利便的添加交互变乱监听,由于canvas内不存在“元素”这个观念,他们仅仅是canvas绘制出来的图形。这对付交互开拓来说是一个必经障碍,想要监听图形的点击变乱思绪很简朴,只要监听canvas元素自己的点击变乱,再判定点击坐标位于哪一个图形内部,就变相实现了图形点击变乱。本文将先容三种要领,判定坐标点是否位于某个canvas图形内部。

约定

本文先容的三种要领合用于辨认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 }

射线法有一种非凡环境,当点在多变形的一条边上时必要非凡处理赏罚。但在工程中我以为也可以不处理赏罚,由于假如用户恰恰点在图形的界线上,那么措施以为他没有点到也讲的已往。

总结

以上三种要领都可以实现canvas中犯科则图形的点击检测。个中,像素法的上风在于不挑外形,并且在静态场景中有必然的机能上风;角度法应该说只有理论代价,适用性不佳;工程中最适用的当属射线法,范围性小,实现简朴,大都时辰只必要知道射线法就可以了。
 

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读