【问题标题】:canvas isPointInPath does not work with ctx.drawImage()canvas isPointInPath 不适用于 ctx.drawImage()
【发布时间】:2012-01-26 22:51:24
【问题描述】:
  1. 我想这不起作用,因为画布正在绘制矢量的位图(并且位图不是路径)。
  2. 即使它确实有效,位图也可能总是有一个矩形许可。

在使用drawImage 时,有没有办法利用isPointInPath 之类的东西?

示例:

  • 顶部画布是使用drawImage 绘制的,而isPointInPath 不起作用。
  • 底部画布使用arcisPointInPath作品绘制。

a link to my proof

** 编辑 **

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

【问题讨论】:

  • 问题看不懂。您想测试图像中的某个像素是否透明?
  • @MikkoOhtamaa 我对我的问题进行了编辑。希望我的补充能澄清这个问题。

标签: html canvas drawimage


【解决方案1】:

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

当您调用 ctx.stroke()ctx.fill() 时,画布会描边或填充该路径。

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

这条路径是isPointInPath 测试的唯一东西。

如果您想测试是否在您绘制的图像或使用ctx.fillRect() 绘制的矩形中,则无法使用内置方法。

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

如果您正在寻找如何对图像进行像素完美(而不仅仅是图像矩形)命中检测,这里讨论了各种方法:Pixel perfect 2D mouse picking with Canvas

【讨论】:

    【解决方案2】:

    您可以尝试重新实现 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));
    

    注意:如果你不小心,你可能会得到一些副作用,比如矩形出现在图像上,或者从后面渗出。

    【讨论】:

    • 您可以通过不中风()或填充()路径来避免流血。只需测试它并扔掉它。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      我遇到了更多挑战,因为我的画布元素可以重新缩放。所以首先当我绘制图形时,在我的例子中,我将它们与名称一起保存在一个数组中并绘制它们:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-07
        • 2018-12-13
        • 2014-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多