Определить, находится ли мышь над объектом внутри холста

Я создал линию внутри элемента холста. Я ищу самый простой способ определить, находится ли положение мыши внутри линии, которая находится внутри холста.

Я использовал эту функцию, чтобы увидеть положение мыши внутри холста, но я очень смущен тем, как мне действовать дальше.

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

Я также просмотрел эту тему Fabricjs обнаруживает мышь над путем к объекту , но это определяет, находится ли мышь внутри холста, а не внутри объекта.

Линия, которую я создаю, является частью более мелких линий, соединенных друг с другом.

 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.

Спасибо, Димитра.


person Dimitra Micha    schedule 04.06.2014    source источник


Ответы (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 плохо работает со строками, потому что теоретически строки имеют нулевую ширину для «попадания».

person markE    schedule 04.06.2014
comment
Большое спасибо за ответ. Мне было интересно, могу ли я использовать это с изогнутой линией (которая является частью большего количества линий). Я отредактирую свой вопрос, чтобы прояснить, как я создаю эту строку до сих пор. - person Dimitra Micha; 04.06.2014
comment
Если ваш путь закрыт, вы можете использовать isPointInPath, чтобы увидеть, находится ли мышь внутри вашего закрытого пути. Существует новый isPointInStroke, который поддерживается в современных браузерах. isPointInStroke проверит путь линии. В противном случае вам придется сделать это вручную, как в моем ответе. Другой способ — получить все пиксельные данные о холсте, а затем проверить, является ли пиксель под мышью непрозрачным (находится на линии) или прозрачным (находится не на линии). - person markE; 04.06.2014
comment
Нет, мой путь не закрыт. Итак, я думаю, я не могу использовать «isPointInStroke». Я нашел эту ссылку neimke.blogspot. nl/2011/03/ , возможно, есть более простое решение для того, что я ищу. - person Dimitra Micha; 04.06.2014
comment
Если вы можете терпеть некоторые ложные срабатывания, вы все равно можете использовать isPointInPath. Пример: jsfiddle.net/m1erickson/2hYHa Хит-тест isPointInPath незаметно закроет для вас путь и нажмите проверить закрытый путь. - person markE; 04.06.2014
comment
...А вот пример, который считывает пиксели с холста. Вы можете протестировать этот массив пикселей, чтобы увидеть, находится ли мышь над непрозрачным пикселем (над частью линии): jsfiddle.net/m1erickson/K2PDZ - person markE; 04.06.2014
comment
...И если ваши фигуры можно свести к прямоугольникам или кругам (или комбинациям прямоугольников и кругов), то вы можете легко использовать математику, чтобы проверить, находится ли мышь внутри прямоугольной или круглой формы. - person markE; 04.06.2014
comment
Большое спасибо за ваши усилия. Массив пикселей у меня действительно работает, хотя у меня программа вылетает (из-за огромной ширины холста, который у меня, наверное, но попробую решить). Я принял ваш ответ, так как с самого начала не дал понять, какая у меня линия. - person Dimitra Micha; 05.06.2014
comment
Если большая часть вашего холста огромной ширины прозрачна (вероятно, так), то вы можете заставить массив пикселей работать с меньшими ресурсами, создав массив только с информацией об альфа-пикселях (вам не нужны значения красного, зеленого, синего только для проверьте, является ли пиксель прозрачным). И вместо того, чтобы загружать сразу весь холст с пиксельными данными, вы можете сделать getImageData в разделах: (1) .getImageData для левой половины холста (2) загрузить данные в альфа-массив (3) .getImageData для правой половина холста (4) загружает данные в альфа-массив. Ваше здоровье! - person markE; 05.06.2014
comment
Действительно, мой холст прозрачен, но я не могу заставить его работать для альфы. Я не уверен, почему. Я пробовал var d=ctx.getImageData(0,0,canvas.width,canvas.height).data[3], но думаю, что это неправильно. Какие-либо предложения? :D - person Dimitra Micha; 05.06.2014