跳到主要内容

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

可以使用两种方式更改图形的命中区域:hitFunchitStrokeWidth 属性。

1. 什么是 hitFunc

要使用 Konva 为图形创建自定义命中绘制函数,可以设置 hitFunc 属性。Konva 使用命中绘制函数绘制用于命中检测的区域。 自定义命中绘制函数有多种用途。例如,你可以扩大命中区域, 让用户更容易与图形交互。你也可以检测图形的某些部分并忽略其他部分, 或简化命中绘制函数以提高渲染性能。

另请参阅编写自定义 sceneFunc最佳实践,这些实践也适用于 hitFunc

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

2. 什么是 hitStrokeWidth

对于 Konva.Line 等图形,覆盖 hitFunc 很困难。有时,你只想加粗事件命中区域。此时,最好为 hitStrokeWidth 属性设置较大的值。

操作说明:在星形上触发 mouseover、mouseout、mousedown 和 mouseup。 你会看到命中区域是一个包围图形的大圆。也请对线条执行相同操作。 你还可以切换命中 Canvas 来查看其外观。这对调试很有用。

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,
});

// custom hit function
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 = 'Toggle hit canvas';
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 + ' star');
});

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

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