【背景】canvas事件检测是一个很常见的问题,目前常用的有几种:
- 用isPointInStroke 或isPointInPath检测
- 用点击位置与各要素线的距离来进行运算,对面等要素来说比较困难
- open layers 2.*版本中涉及到一个很精巧的办法,要素ID转化为color,通过点击事件取color,反求要素ID
针对第3种情况,进行一些说明。代码来自lib/render/canvas
关键属性和方法:
hitDetection : feature碰撞检测; 用于解决extranelGraphics绘制与获取.
hitOverflow : 存储碰撞溢出值, 用于分辨两个不同的要素, 最多16777215; 如果两个要素id相差超过这个值将不能够被正确检测;因为从颜色反取的ID
featureIdToHex : 将feature.id转换成RGB Hex值;
setHitContextStyle : 利用featureIdToHex将featureId转换成rgb颜色值, 然后根据图形形状在hitContext绘制对应颜色的要素;这样, 就实现了通过hit方式方向查询到featureId的解决方案; 最终都在getFeatureIdFromEvent方法里得到体现;
-
getFeatureIdFromEvent : 只有在hitDetection开启时返回feature, 否则返回
var data = this.hitContext.getImageData(x, y, 1, 1).data; -> 获取RGB像素值;
然后将RGB像素值转换成Hex值;
Hex值再经过处理, id – 1 + this.hitOverflow 即是 featureId;
Hex值FFFFFF : 16777215;
总结:核心思路是利用唯一ID及颜色的转换,来快速检索要素,思路很巧,
问题
如果要素相交,相交处检测是否有颜色偏差,还需测试确认
其他思路
- mapv 利用重绘、isPointInStroke or isPointInPath来检测,检测效率略低,复杂度O(n)
- zrender 每一个要素记录其mbr, 循环检测,首先检测点与mbr相交,然后用数学方法来检测是否在要素上 ,复杂度O(n)
- 其他,可以结合Rtree, 对所有要素建立mbr索引,先快速检测,再精确检测,复杂度O(logn) ++