【问题标题】:Canvas - detect click outside clipped area画布 - 检测剪切区域外的点击
【发布时间】:2016-06-01 18:10:36
【问题描述】:

我在地图上有一个区域被剪掉了!是否可以在剪切区域外点击检测,所以如果人们点击黑色变暗区域,它会显示警报?

这是我的代码:

var canvas  = document.getElementById("canvas");
var ctx     = canvas.getContext("2d");
var image   = new Image;

image.addEventListener('load', function(){

  ctx.drawImage(image, 0, 0, canvas.width, canvas.height);

  ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
  ctx.fillRect(0, 0, 870, 500);

  // Use save and restore to make sure the canvas restores its non-clipping path setup after clipping
  ctx.save();
  ctx.beginPath();
  ctx.moveTo(10, 10);
  ctx.lineTo(100,50);
  ctx.lineTo(100, 100);
  ctx.lineTo(200, 150);
  ctx.lineTo(10, 150);
  ctx.closePath();
  // Use the path just created as a clipping path
  ctx.clip();
  // Draw anywhere in the image, only inside the clipping path will be drawn
  ctx.drawImage(image,0,0, canvas.width, canvas.height);
  // restore so you can draw outside the clipping path again
  ctx.restore();

});

image.src = 'http://www.marinadivenezia.it/media/467/w-876/h-506/00-MAPPA-2015-GENERICA.jpeg';

我的小提琴代码在这里: http://jsfiddle.net/eGjak/2789/

问候安德烈亚斯

【问题讨论】:

  • 是的,您可以检测点击事件的 X-Y 坐标,通过该详细信息您可以知道点击是在路径内还是在路径外。
  • 如果剪辑区域是一个多边形,你可以看看这个How can I determine whether a 2D Point is within a Polygon?
  • @jcubic 这是通过方法 isPointInPath()(和 isPointInStroke())内置的,包括奇偶和非零绕组测试。

标签: javascript jquery canvas html5-canvas


【解决方案1】:

使用普通路径

当然可以,但是让我们稍微重构一下代码以便重用。如果您将剪切路径提取到单独的函数中,以便我们可以将其重用于命中测试:

function makePath() {
  ctx.beginPath();
  ctx.moveTo(10, 10);
  ctx.lineTo(100,50);
  ctx.lineTo(100, 100);
  ctx.lineTo(200, 150);
  ctx.lineTo(10, 150);
  ctx.closePath();
}

然后我们可以使用它来创建剪辑:

  //...
  ctx.save();
  makePath();   // here
  ctx.clip();
  ctx.drawImage(image,0,0, canvas.width, canvas.height);
  ctx.restore();
  //...

以及命中测试,尽管我们会反转布尔结果以触发路径外的点击。对于命中测试,我们可以使用isPointInPath(),它将使用当前路径,默认情况下使用非零缠绕规则:

canvas.onclick = function(e) {
  var rect = this.getBoundingClientRect(),
      x =   e.clientX - rect.left,
      y = e.clientY - rect.top;
    
  makePath();  // and here
  if (!ctx.isPointInPath(x, y)) alert("Outside");
};

您还可以将路径存储在 Path2D 对象中,而不是像此处那样存储在函数中,具体取决于您希望支持的新浏览器。

Modified fiddle

使用 Path2D

我们可以使用Path2D 对象来代替函数,该对象可以像这样重用。这些对象可以方便地存储多个路径数据,无需重新构建您要测试的每个路径。缺点是目前并非所有浏览器都支持它们。

var p = new Path2D();
p.moveTo(10, 10);
p.lineTo(100,50);
p.lineTo(100, 100);
p.lineTo(200, 150);
p.lineTo(10, 150);
p.closePath();

然后用它来剪辑:

  ctx.save();
  ctx.clip(p);  // hand over path object
  ctx.drawImage(image,0,0, canvas.width, canvas.height);
  ctx.restore();

以及命中测试:

if (!ctx.isPointInPath(p, x, y)) alert("Outside");

Modified fiddle

【讨论】:

  • 这很好用,谢谢!有没有办法帮助点击错误的用户,所以如果他们在外点击,我会强制鼠标点击在剪切区域,接近他们在外面点击的点击?
  • @AndreasBaran 没问题!您可以使用插值将路径分解为点数组,然后测量到每个点的距离以找到最接近的点,然后如果鼠标点击在外面,则将坐标锁定到每个点。一种方法可能是this answer
猜你喜欢
  • 2013-05-02
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
相关资源
最近更新 更多