javascript 检测鼠标是否在画布内的对象上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24043967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 02:03:17  来源:igfitidea点击:

Detect if Mouse is over an object inside canvas

javascripthtmlhtml5-canvasmouseovermouseout

提问by Dimitra Micha

I have created a line inside a canvas element. I am looking for the easiest way to detect if the position of the mouse is inside the line, which is inside the canvas.

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

I have used this function to see the position of the mouse inside the canvas, but I am very confused on how I should proceed.

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

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

I have also looked at this topic Fabricjs detect mouse over object path, but it detects if the mouse is inside the canvas, not inside the object.

我也看过这个主题Fabricjs 检测鼠标悬停在对象路径上,但它检测鼠标是否在画布内,而不是在对象内。

The line that I create is a part of smaller lines, connected to each other.

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

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

            }

where x[i] and y[i] are the arrays with the coordinates that I want.

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

I hope my question is clear, although I am not very familiar with javascript.

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

Thanks Dimitra

谢谢迪米特拉

回答by markE

A Demo: http://jsfiddle.net/m1erickson/Cw4ZN/

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

enter image description hereenter image description here

在此处输入图片说明在此处输入图片说明

You need these concepts to check if the mouse is inside a line:

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

  • Define the starting & ending points of a line

  • Listen for mouse events

  • On mousemove, check if the mouse is within a specified distance of the line

  • 定义一条线的起点和终点

  • 监听鼠标事件

  • 在 mousemove 上,检查鼠标是否在线的指定距离内

Here's annotated example code for you to learn from.

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

$(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>

About hit-testing Paths:

关于命中测试路径:

If you create Paths using path commands you can use context.isPointInPath(mouseX,mouseY) to check if the mouse is inside a path. context.isPointInPath does not work well with lines however because lines theoretically have zero width to "hit".

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