Skip to main content

HTML5 Canvas 自定义命中检测函数教程

改变图形命中区域有两种方式:hitFunchitStrokeWidth 属性。

1. 什么是 hitFunc

要为 Konva 中的图形创建自定义命中绘制函数,可以设置 hitFunc 属性。命中绘制函数是 Konva 用来绘制用于命中检测的区域的函数。使用自定义命中绘制函数有多种好处,比如使命中区域更大,方便用户与图形交互;只让图形的某些部分可以被检测到,其他部分则不行;或者简化命中绘制函数以提升渲染性能。

另外,可以查看一些编写自定义 sceneFunc最佳实践sceneFunc 也可用于 hitFunc

hitFunc 是一个带有两个参数的函数:Konva.Context 渲染器和一个图形实例。

2. 什么是 hitStrokeWidth

对于某些图形,比如 Konva.Line,覆盖 hitFunc 太困难。在某些情况下,你可能只是想让它的事件响应范围更宽一点。这种情况下,最好使用 hitStrokeWidth 属性设置一个较大的值。

操作说明:在星形上进行 mouseover、mouseout、mousedown 和 mouseup 操作,观察命中区域是一个包裹图形的超大圆。对线条也试试看。同时你可以切换命中画布,观察其显示效果,这对调试很有用。

import Konva from 'konva';

const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});

const layer = new Konva.Layer();
stage.add(layer);

const text = new Konva.Text({
x:10,
y: 10,
text: '',
fontSize: 24,
});
layer.add(text);

const star = new Konva.Star({
x: stage.width() / 4,
y: stage.height() / 2,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
});

// 自定义命中函数
star.hitFunc(function (context) {
context.beginPath();
context.arc(0, 0, 70, 0, Math.PI * 2, true);
context.closePath();
context.fillStrokeShape(this);
});

const line = new Konva.Line({
x: stage.width() * 0.6,
y: stage.height() / 2,
points: [-50, -50, 50, 50],
stroke: 'black',
strokeWidth: 2,
hitStrokeWidth: 20,
});

const button = document.createElement('button');
button.innerHTML = '切换命中画布';
document.body.appendChild(button);
let showHit = false;

button.addEventListener('click', () => {
showHit = !showHit;
if (showHit) {
stage.container().style.border = '2px solid black';
stage.container().style.height = stage.height() + 'px';
stage.container().appendChild(layer.hitCanvas._canvas);
layer.hitCanvas._canvas.style.position = 'absolute';
layer.hitCanvas._canvas.style.top = 0;
layer.hitCanvas._canvas.style.left = 0;
} else {
layer.hitCanvas._canvas.remove();
}
});

function writeMessage(message) {
text.text(message);
}

star.on('mouseover mouseout mousedown mouseup', function (evt) {
writeMessage(evt.type + ' 星形');
});

line.on('mouseover mouseout mousedown mouseup', function (evt) {
writeMessage(evt.type + ' 线条');
});

layer.add(star);
layer.add(line);