Canvas isPointInPath()具有多个路径

时间:2015-01-08 22:29:22

标签: javascript html5 canvas

我有一个名为Box的画布“对象”,当鼠标悬停在它上面时我需要检测。

我有一个这个对象的draw()方法,我使用的是isPointInPath()方法,但只有在光标位于最后一个路径时才会改变。有什么建议吗?

Box.prototype.draw = function() {

    this.ctx.beginPath();
    this.ctx.moveTo(this.matrix.p1.x, this.matrix.p1.y);
    this.ctx.lineTo(this.matrix.p2.x, this.matrix.p2.y);
    this.ctx.lineTo(this.matrix.p3.x, this.matrix.p3.y);
    this.ctx.lineTo(this.matrix.p4.x, this.matrix.p4.y);
    this.ctx.lineTo(this.matrix.p1.x, this.matrix.p1.y);
    this.ctx.closePath();

    this.ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
    this.ctx.fill();

    if (this.ctx.isPointInPath(mouse.x, mouse.y)) {
        this.canvas.style.cursor = 'pointer';
        this.ctx.fillStyle = 'rgba(0, 0, 255, 0.5)';
        this.ctx.fill();
        return;
    }

    this.canvas.style.cursor = 'default';

};

2 个答案:

答案 0 :(得分:5)

context.isPointInPath仅测试最后定义的路径(来自最后一个context.beginPath)。

因此,您必须单独测试每个形状路径:

  • “重新定义”第一个形状。重新定义意味着重新发出第一个形状的路径命令 - 但您不需要实际描边()或填充()第一个形状。

  • 使用isPointInPath测试鼠标是否在第一个形状内。

  • 继续测试第二,第三,......最后一个形状。

顺便说一句,如果你的所有形状都是矩形,你可以使用数学来测试鼠标是否在任何矩形内:

var isInside=(
    mouseX>=RectX && 
    mouseX<=RectX+RectWidth &&
    mouseY>=RectY &&
    mouseY<=RectY+RectHeight
);

答案 1 :(得分:5)

您可以将每个路径存储在数组或对象中以便以后访问它们。

通常,您需要创建Path2D。 (使用前请检查浏览器支持)。

这是一个非常简单的六边形网格来演示这个: http://codepen.io/pixelass/pen/37445407893ef783e414ce136af5633a

const C = document.createElement('canvas');
const $ = C.getContext('2d');

const rows = 5;
const cols = 5;
var side = 50;
C.width = cols * side * Math.sqrt(3);
C.height = rows * 1.5 * side;

const paths = [];

var dy = -1;
for (let i = 0; i < (rows + 1) * (cols + 1); i++) {
  let dx = i % (cols + 1);
  dy += dx ? 0 : 1;
  dx += dy % 2 ? -.5 : 0;
  let cx = dx * (side * Math.sqrt(3)) + side / 2 * Math.sqrt(3);
  let cy = (dy - .5) * (side * 1.5) + side;
  let path = new Path2D();
  for (let j = 0; j < 6; j++) {
    let x = Math.cos(Math.PI / 3 * j + Math.PI / 6) * side + cx;
    let y = Math.sin(Math.PI / 3 * j + Math.PI / 6) * side + cy;
    if (j) {
      path.lineTo(x, y);
    } else {
      path.moveTo(x, y);
    }
  }
  path.closePath();
  $.fillStyle = `hsl(${10*i},50%,50%)`;
  $.fill(path);
  paths.push(path);
}

C.addEventListener('mousemove', e => {
  let bound = C.getBoundingClientRect();
  let x = e.pageX - bound.top;
  let y = e.pageY - bound.left;
  paths.forEach((path, index) => {
    if ($.isPointInPath(path, x, y)) {
      console.log(index);
    }
  });
});

document.body.appendChild(C);