【问题标题】:Detect if Mouse is over an object inside canvas检测鼠标是否在画布内的对象上
【发布时间】:2014-07-25 11:44:00
【问题描述】:

我在画布元素内创建了一条线。我正在寻找最简单的方法来检测鼠标的位置是否在画布内的线内。

我已经使用这个函数来查看鼠标在画布内的位置,但我对如何进行操作感到非常困惑。

function getMousePos(c, evt) {
            var rect = c.getBoundingClientRect();
            return {
                x: evt.clientX - rect.left,
                y: evt.clientY - rect.top
            };
        }

我也看过这个主题 Fabricjs detect mouse over object path ,但它会检测鼠标是否在画布内,而不是在对象内。

我创建的线是较小线的一部分,它们相互连接。

 for (var i = 0; i < 140 ; i++) {

                ctx.beginPath();

                ctx.moveTo(x[i],y[i]);
                ctx.quadraticCurveTo(x[i],50,x[i+1],y[i+1]);
                ctx.lineWidth = 40;

                ctx.strokeStyle = 'white';
                ctx.lineCap = 'round';
                ctx.stroke();

            }

其中 x[i] 和 y[i] 是具有我想要的坐标的数组。

我希望我的问题很清楚,尽管我对 javascript 不是很熟悉。

谢谢 迪米特拉

【问题讨论】:

标签: javascript html html5-canvas mouseover mouseout


【解决方案1】:

演示:http://jsfiddle.net/m1erickson/Cw4ZN/

您需要这些概念来检查鼠标是否在一行内:

  • 定义线的起点和终点

  • 监听鼠标事件

  • 在鼠标移动时,检查鼠标是否在该线的指定距离内

这里有带注释的示例代码供您学习。

$(function() {

  // canvas related variables
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
  var $canvas = $("#canvas");
  var canvasOffset = $canvas.offset();
  var offsetX = canvasOffset.left;
  var offsetY = canvasOffset.top;

  // dom element to indicate if mouse is inside/outside line
  var $hit = $("#hit");

  // determine how close the mouse must be to the line
  // for the mouse to be inside the line
  var tolerance = 5;

  // define the starting & ending points of the line
  var line = {
    x0: 50,
    y0: 50,
    x1: 100,
    y1: 100
  };

  // set the fillstyle of the canvas
  ctx.fillStyle = "red";

  // draw the line for the first time
  draw(line);

  // function to draw the line
  // and optionally draw a dot when the mouse is inside
  function draw(line, mouseX, mouseY, lineX, lineY) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.moveTo(line.x0, line.y0);
    ctx.lineTo(line.x1, line.y1);
    ctx.stroke();
    if (mouseX && lineX) {
      ctx.beginPath();
      ctx.arc(lineX, lineY, tolerance, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fill();
    }
  }

  // calculate the point on the line that's 
  // nearest to the mouse position
  function linepointNearestMouse(line, x, y) {
    //
    lerp = function(a, b, x) {
      return (a + x * (b - a));
    };
    var dx = line.x1 - line.x0;
    var dy = line.y1 - line.y0;
    var t = ((x - line.x0) * dx + (y - line.y0) * dy) / (dx * dx + dy * dy);
    var lineX = lerp(line.x0, line.x1, t);
    var lineY = lerp(line.y0, line.y1, t);
    return ({
      x: lineX,
      y: lineY
    });
  };

  // handle mousemove events
  // calculate how close the mouse is to the line
  // if that distance is less than tolerance then
  // display a dot on the line
  function handleMousemove(e) {
    e.preventDefault();
    e.stopPropagation();
    mouseX = parseInt(e.clientX - offsetX);
    mouseY = parseInt(e.clientY - offsetY);
    if (mouseX < line.x0 || mouseX > line.x1) {
      $hit.text("Outside");
      draw(line);
      return;
    }
    var linepoint = linepointNearestMouse(line, mouseX, mouseY);
    var dx = mouseX - linepoint.x;
    var dy = mouseY - linepoint.y;
    var distance = Math.abs(Math.sqrt(dx * dx + dy * dy));
    if (distance < tolerance) {
      $hit.text("Inside the line");
      draw(line, mouseX, mouseY, linepoint.x, linepoint.y);
    } else {
      $hit.text("Outside");
      draw(line);
    }
  }

  // tell the browser to call handleMousedown
  // whenever the mouse moves
  $("#canvas").mousemove(function(e) {
    handleMousemove(e);
  });

}); // end $(function(){});
body {
  background-color: ivory;
}

canvas {
  border: 1px solid red;
}
<!doctype html>
<html>

<head>
  <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
  <!-- reset css -->
  <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

</head>

<body>
  <h2 id="hit">Move mouse near line</h2>
  <canvas id="canvas" width=300 height=300></canvas>
</body>

</html>

关于命中测试路径:

如果您使用路径命令创建路径,您可以使用 context.isPointInPath(mouseX,mouseY) 检查鼠标是否在路径内。 context.isPointInPath 不能很好地处理线条,因为理论上线条的“命中”宽度为零。

【讨论】:

  • 非常感谢您的回答。我想知道我是否可以将它与曲线一起使用(这是更多线条的一部分)。我将编辑我的问题,以明确到目前为止我是如何创建这一行的。
  • 如果您的路径是封闭的,那么您可以使用isPointInPath 来查看鼠标是否在您的封闭路径内。现代浏览器支持新的isPointInStroke。 isPointInStroke 将对线路径进行命中测试。否则,您将不得不像我的回答中那样“手动执行”。另一种方法是获取画布的所有像素数据,然后检查鼠标下的像素是不透明的(在线上)还是透明的(不在线上)。
  • 不,我的路径没有关闭。所以,我想我不能使用'isPointInStroke'。我找到了这个链接neimke.blogspot.nl/2011/03/…,也许有一个更简单的解决方案可以满足我的需求。
  • 如果您可以容忍一些误报,您仍然可以使用isPointInPath。示例:jsfiddle.net/m1erickson/2hYHa isPointInPath 命中测试将为您“无形地关闭”路径并命中测试关闭的路径。
  • ...这是一个从画布读取像素的示例。您可以测试此像素阵列以查看鼠标是否在不透明像素上(在线条的一部分上):jsfiddle.net/m1erickson/K2PDZ
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 2016-07-22
相关资源
最近更新 更多