canvas按钮点击事件,canvas点击后触发事件

  canvas按钮点击事件,canvas点击后触发事件

  canvas的内部元素并不能像DOM元素那样方便地添加交互事件监控,因为canvas中没有“元素”的概念,它们只是canvas绘制的图形。这是交互开发的必要障碍。监控图形的点击事件的想法非常简单。只要你监控canvas元素本身的点击事件,然后判断点击坐标位于哪些图形中,就可以变相实现图形的点击事件。本文将介绍三种判断坐标点是否位于画布内部的方法。

  约定

  本文介绍的三种方法适用于识别画布中形状不规则、位置不规则的图形点击事件。对于形状规则或者位置规则的场景,肯定有更简单的实现,这里不讨论。

  像素法

  像素检测法的思路是从屏幕上分别在画布中绘制多个图形(如果有多个图形),通过getImageData()方法获取像素数据并保存。canvas元素在监测click事件时,可以通过点击坐标直接计算出点击发生在画布上的哪个像素,然后遍历之前保存的图形数据,看这个像素的alpha值是否为0。如果为0,表示着陆点不在当前图形中,否则表示图形被点击。

  根据点击坐标获取被点击像素的序号的方法:

  像素数=(纵坐标-1) *画布宽度横坐标

  比如在宽度为5的画布上点击坐标(3,3),根据上面的公式,像素数为(3-1)* 5 ^ 3=18,如图:

  因为canvas导出的图形数据是按照rgba顺序将每个像素存储在一个4个数的数组中,所以如果要访问指定像素的alpha值,只需要读取这个数组的第3个Pindex * 4值即可。如果该值不为0,则表示该像素可见,即图形被单击。

  我觉得这种方法是最直接的思维方式,最准确的结果,对图形的形状没有要求。然而,这种方法有一个致命的局限性。当图形需要在画布上移动时,需要频繁创建数据缓存以保证检测结果的准确性。由于画布大小和图形数量的影响,getImageData()方法的性能会成为一个严重的瓶颈。所以,如果画布图形是静态的,这种方法非常适合,否则,就不适合这种方法。

  角度法

  角度判断的原理很好理解。如果一个点在多边形内,则该点与多边形所有顶点形成的角度应该正好等于360度。

  计算过程可以转化为以下三个步骤:

  1.已知多边形的顶点和坐标,将两组坐标和顶点组合成三点队列

  2.知道三点之间的夹角就可以用宇轩定理。

  3.判断夹角之和是否为360。

  每个步骤都非常简单,实现如下:

  //计算两点之间的距离const get distance=function (p1,p2){ return math . sqrt((P1 . x-p2 . x)*(P1 . x-p2 . x)(P1 . y-p2 . y)*(P1 . y-p2 . y))};angle方法确定点在多边形const checkpointinpolyline=(point,polyline points)={ letto tala=0;const A=点;for(设I=0;I折线点.长度;i ) {设B,C;if(I===polyline points . length-1){ B={ x:polyline points[I][0],y:polyline points[I][1]};C={ x: polylinePoints[0][0],y:polyline points[0][1]};} else { B={ x:polyline points[I][0],y:polyline points[I][1]};C={ x: polylinePoints[i 1][0],y:polyline points[I 1][1]};}//计算角度常数anglea=math . acos((math . power(get distance(a,c),2) math.power (get distance (a,b),2)-math.power (get distance (b,c)),2)/(2 * GetDistence (a,c) * GetDistence (a,b)))Totala=anglea }//判断角度之和Return Totala==2 * math.pi}这种方法有一个限制,就是图形必须是凸多边形。如果不是凸多边形需要切割成凸多边形再计算的话,会比较复杂。

  一个类似的想法是面积法。如果一个点在多边形内,由该点和多边形所有顶点形成的三角形的面积应该等于多边形的面积。首先计算多边形的面积是很麻烦的,所以这种方法可以直接跳过。

  射线法

  射线法是一种我说不出真相的方法,但是很有用。只要判断点与多边形一边的交点个数为奇数,该点就在多边形内部。注意,只要数一下两边的焦点数量,比如左边。这种方法不限制多边形的类型,凸多边形、凹多边形甚至环形都可以。

  实施起来也非常简单:

  const checkpointinpolyline=(point,polylinepoints)={//ray方法let left side=0;const A=点;for(设I=0;I折线点.长度;i ) {设B,C;if(I===polyline points . length-1){ B={ x:polyline points[I][0],y:polyline points[I][1]};C={ x: polylinePoints[0][0],y:polyline points[0][1]};} else { B={ x:polyline points[I][0],y:polyline points[I][1]};C={ x: polylinePoints[i 1][0],y:polyline points[I 1][1]};}//判断左交点let sortbyy=[b.y,c.y]。sort ((a,b)=a-b)if(sort byy[0]a . y sort byy[1]a . y){ if(b . xa . x c . x a .但是在工程上,我觉得没必要处理,因为如果用户只是指向图的边界,那么程序就认为他没有指向过去。

  总结

  以上三种方法都可以实现画布中不规则图形的点击检测。其中像素法的优势在于不挑形状,在静态场景下有一定的性能优势。从视角上,应该说法律只有理论价值,实用性差;最实用的项目是射线法,局限性小,实现简单。很多时候,你只需要知道射线法就可以了。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: