本文是 Canvas 检测某点是否在图形内的第三篇,前两篇分别介绍了使用[几何方法实现检测的 Fabric.js] 、使用[透明度实现检测的 Create.js] 。本文主要介绍使用随机颜色实现检测的 Konva.js。Konva.js 和 Create.js 都是用颜色值的方式来检测点是否在图形内部,虽然大体上原理是一致的,但是实现的细节上有一定的区别。
Konva.js 会为画布中每个图形元素产生一个随机的颜色值 colorKey。在渲染过程中,除了生成一个为用户展示的 sceneCanvas 之外,还会在内存中产生一个用于检测的 hitCanvas。所有的图形都会在这个 hitCanvas 重新绘制一遍,并且各个图形的大小和位置属性也保持一致,但是图形内填充的颜色却是对应的 colorKey 值。在用户点击发生点击行为之后,通过获取 hitCanvas 上点击位置的颜色值(即 colorKey),就可以找到 sceneCanvas 中哪个图形元素被点击了。
如下图所示,左侧的是正常渲染的 sceneCanvas,右侧的是 hitCanvas。hitCanvas 里面的每个图形所对应的颜色都是唯一的,通过颜色与图形的对应关系,可以很容易定位出哪个元素被点击了。随机的 hex 颜色最多会会有 256 * 256 * 256 = 16777216 种,也就是说在 Konva.js 最多支持 16777216 个图形做点击检测,这个数量也足够我们开发使用了。
Konva.js 生成随机颜色代码:
constructor(config) {
super(config);
// set colorKey
let key;
while (true) {
// 生成随机颜色
key = Util.getRandomColor();
if (key && !(key in shapes)) {
break;
}
}
this.colorKey = key;
// window.Konva.shapes
shapes[key] = this;
}
Konva.js 判断点是否在图形内部代码:
_getIntersection(pos) {
const ratio = this.hitCanvas.pixelRatio;
const p = this.hitCanvas.context.getImageData(Math.round(pos.x * ratio), Math.round(pos.y * ratio), 1, 1).data;
const p3 = p[3];
// fully opaque pixel
if (p3 === 255) {
const colorKey = Util._rgbToHex(p[0], p[1], p[2]);
const shape = shapes[HASH + colorKey];
// 找到对应的图形
if (shape) {
return {
shape: shape,
};
}
return {
antialiased: true,
};
}
else if (p3 > 0) {
// antialiased pixel
return {
antialiased: true,
};
}
// empty pixel
return {};
}
当点击多个图形的重叠区域时,这种方法只能最上层被点击的图形,其他的图形会被忽略。在这种情况下, Konva.js 提供了 getAllIntersections(pos) 方法可获取到所有被点击的图形,这个方法的实现原理与 Create.js 的实现方案是一样的:在内存中将每个图形渲染,判断对应点的透明度是否大于 0 。每个图形做一次渲染和判断,会对性能造成一定的影响,下面是该方法在官方文档中的说明:
getAllIntersections(pos): get all shapes that intersect a point. Note: because this method must clear a temporary canvas and redraw every shape inside the container, it should only be used for special situations because it performs very poorly. Please use the Konva.Stage#getIntersection method if at all possible because it performs much better.
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8