canvas isPointInPath不能与ctx.drawImage()一起使用

时间:2011-12-23 16:33:50

标签: html5 canvas drawimage

  1. 我认为这不起作用,因为画布正在绘制矢量的位图(并且位图不是路径)。
  2. 即使它确实有效,位图也可能总是有一个矩形的许可证。
  3. 使用isPointInPath时,有没有办法利用drawImage之类的内容?

    示例:

    • 使用drawImage绘制顶部画布,isPointInPath不起作用。
    • 底部画布使用arcisPointInPath工作。

    a link to my proof

    **编辑**

    我在一个画布上绘制一个圆圈,并使用isPointInPath查看鼠标指针是否位于圆圈内(我的示例中为底部画布)。 我还使用drawImage将底部画布“复制”到顶部画布。请注意,isPointInPath不能在顶部画布上工作(很可能是由于我上面提到的原因)。有没有我可以使用的解决方案,适用于任何类型的路径(或位图)?

4 个答案:

答案 0 :(得分:3)

画布上下文有一个称为当前路径的隐藏事物。 ctx.beginPathctx.lineTo等创建此路径。

当您调用ctx.stroke()ctx.fill()画布笔划或填充该路径时。

即使在描边或填充之后,路径仍然存在于上下文中。

此路径是isPointInPath测试的唯一事物。

如果你想测试你绘制的图像中是否有某个东西或者用ctx.fillRect()绘制的矩形,那么使用内置方法是不可能的。

通常,您希望使用自己编写的is-point-in-rectangle函数(或从其他人那里获取)。

如果您正在寻找如何对图像进行像素完美(而不仅仅是图像矩形)点击检测图像,可以采用多种方法执行此处讨论:Pixel perfect 2D mouse picking with Canvas

答案 1 :(得分:1)

您可以尝试重新实现ctx.drawImage()以始终在图像背后绘制一个框,如此(JSFiddle example):

ctx.customDrawImage = function(image, x, y){
    this.drawImage(image, x, y);
    this.rect(x, y, image.width, image.height);
}
var img1 = new Image();
img1.onload = function(){
var x = y = 0;
ctx.drawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));

x = 1.25 * img1.width;
ctx.customDrawImage(img1, x, y);
console.log(ctx.isPointInPath(x + 1, y + 1));

注意:您可能会出现副作用,例如图像上出现的矩形,或者如果您不小心,可能会从后面流血。

答案 2 :(得分:0)

对我来说,在移动画布后isPointInPath失败了。所以,我用过:

mouseClientX -= gCanvasElement.offsetLeft; mouseclientY -= gCanvasElement.offsetTop;

答案 3 :(得分:0)

我还有更多挑战,因为我的canvas元素可以重新缩放。所以首先,当我绘制图形时,在我的情况下是弧,我将它们与名称一起保存在数组中并绘制它们:

      if (this.coInit == false)
      {
        let co = new TempCO ();
        co.name= sensor.Name;
        co.path = new Path2D();
        co.path.arc(c.X, c.Y, this.radius,  0, 2 * Math.PI);
        this.coWithPath.push(co);
      }
      let coWP = this.coWithPath.find(c=>c.name == sensor.Name);
      this.ctx.fillStyle = color;
      this.ctx.fill(coWP.path);

然后在鼠标事件中,遍历所有项目,并检查click事件是否在路径中。但是我还需要根据调整后的画布重新调整鼠标坐标的大小:

getCursorPosition(event) {
  const rect = this.ctx.canvas.getBoundingClientRect();
  const x = ((event.clientX - rect.left ) / rect.width) * this.canvasWidth;
  const y = ((event.clientY - rect.top) / rect.height) * this.canvasHeight;
  this.coWithPath.forEach(c=>{

    if (this.ctx.isPointInPath(c.path, x, y))
    {
      console.log("arc is hit", c);
      //Switch light
    }
  });
}

因此,我得到了画布的当前大小,并将该点重新缩放为原始大小。现在可以了!

TempCO的外观如下:

export class TempCO
{
  path : Path2D;
  name : string;
}