前端 鼠标一次移动半个像素_canvas图形鼠标时间判定的另一种方法

好多人在做canvas图形的时候,想去检测鼠标事件与图形之间的碰撞关系缺不知道咋做,这边其实主流的做法需要用到几何算法判定。首先,需要代码结构里将基本的点线面等图形区分开,然后监听鼠标mousemove事件,一次去与图形做数学上的点和线、面的判定,再具体代码实现的时候需要用到几何与向量的数学知识,或者是用矩阵来做相关运算。这里不去展示这方面的代码(有兴趣的朋友可以留言讨论),提供另外一种方式来做鼠标事件的检测,并对比两种做法的区别与优劣势。

先说说主要思路,再上代码。其实给一个透明的画布(canvas默认就是透明),当绘制图形在上面了,具体的像素点会被着色,着色的单元格(物理像素网格)透明度就不再是0,我们可以通过这种方式来比对鼠标位置和canvas getImageData里的具体某个像素格的alpha通道是不是大于0。首先需要清除css像素格子和物理像素格子之间的关系,这里以devicePixelRatio为2常见的屏幕来做解释。

3415d8abaf3d61c92095672d5df14d71.png

图片里标的1、2、3...8...代表的是css的像素坐标,然后每个格子会被分成4小格(由devicePixelRatio决定),这4个格子就是真正渲染时候用到的最小格子。

假设一个400px * 400px的画布,devicePixelRatio为2,为了保证高清屏的清晰,我们会把canvas.width设为400 * 2 = 800,高度同样设为800,假如鼠标hover的位置css坐标为(2,2),即图上红色和绿色小格子共同组成的大单元格,我们做鼠标在这块有没有hover到图形的检测的话,就是检测这4个小格子的alpha通道是不是大于0,有一个格子满足条件就可以了(注: 这边没有处理鼠标位置的容差,真正这么检测的话,肯定得设置一下容差,不然鼠标位置所在的一个css单元格太小了,交互体验上就是严格在这个小格子里才算hover到了)。

然后我们分析一下canvas的getImageData里面的数据,一个物理像素单元格对应4个通道——r、g、b、a,所以imageData的数组长度就是 物理像素长*物理像素宽*4,这里就是800 * 800 * 4 = 640000个数据,第一个物理像素格子的值保存在0、1、2、3这几个下标里面,3下标存着alpha值,一次类推。这样(2,2)坐标的4个格子的alpha通道的值就存在鼠标下标为6411、6415、9611、9615四个下标里面,具体换算想不通就可以不用继续看了,找出这几个值判断一下就可以了。

demo地址

demo例子可以设置css像素容差,还有考虑了不同dpr的屏幕,当鼠标移动到文字或者那条线上的时候,会同时修改线和文字的颜色。

demo中可以看到我绘制的图形边界,这里可以提到这种思路的另外一个用法了。我们使用几何算法判断鼠标落在文字上的常规做法是,先计算出文字的外包围和,也就是个矩形框,然后判断鼠标点在没在矩形框,这种粗暴简单的做法可以满足大部分场景了,但这边需要先计算好文字的包围和的边界,边界计算这里就不要讨论了,反正包围和本来计算就不是很精确,因为要考虑到不同语言、标点符号等等特殊字符的存在,而且文字里的空白也考虑不了。使用像素来计算的话包围和就会很精确了。但这边计算包围和并不是主要的用途,进一步考虑canvas的优化的话,我们一般会做图形缓存,缓存的画布比较大的话,性能还会有副作用,而计算出的精确边界做缓存的话就会很节省内存,这里当然没考虑那种图形和画布一样大。

这种纯粹像素检测方法可以把文字的hover检测做到物理像素那个级别,已经是最大的极限了,可以说超级精确了。而且对于那种鼠标随意绘制的曲线或者难以用参数来描述的图形,这种无疑提供了一种可用的检测方法。

这里吹了这么多,得说说局限性了。首先可以看到检测的效率严重依赖于画布的大小和dpr的值,因为imageData里的数据长度取决与这两个参数。当然可以通过每个图形缓存一个宽高等于边界的方法来解决,konva这个库就是通过这种缓存策略和检测方法来做鼠标事件的。这里的效率问题自己可以去做详细测试,demo里写的例子,在400 * 400的宽高下,容差设为3px(即同时检测鼠标所在单元格和周围单元格40个格子),费时2.5ms;800 * 800,费时9.5ms,可以看到性能是呈指数增长的,当然这边并没有做到最优化,每次都是以整个画布来检测的,可以像上面的说的只检测文字和线所在的范围内的像素。这里另一个局限性就是适用于图形本身坐标数据不是那么容易改变的条件下了,适用与图形展示上去后,不会轻易改变几何结构。

总结:具体写底层canvas库,数学几何检测和像素检测两种方法可以一块使用,具体需要视业务场景来决定,不能一味采用某种方法来开发。最后,谢谢大家的阅读,如果有这方面的疑问可以留言讨论,canvas的图层组织和几何算法本人都小有研究,并有代码实践,可以共同学习讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值