跳到主要内容

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