Реальное положение мыши в холсте

Я пытаюсь рисовать с помощью мыши над холстом HTML5, но единственный способ, который, кажется, работает хорошо, - если холст находится в позиции 0,0 (верхний левый угол), если я изменю позицию холста, по какой-то причине он не рисует, как должен. Вот мой код.

 function createImageOnCanvas(imageId){
    document.getElementById("imgCanvas").style.display = "block";
    document.getElementById("images").style.overflowY= "hidden";
    var canvas = document.getElementById("imgCanvas");
    var context = canvas.getContext("2d");
    var img = new Image(300,300);
    img.src = document.getElementById(imageId).src;
    context.drawImage(img, (0),(0));
}

function draw(e){
    var canvas = document.getElementById("imgCanvas");
    var context = canvas.getContext("2d");
    posx = e.clientX;
    posy = e.clientY;
    context.fillStyle = "#000000";
    context.fillRect (posx, posy, 4, 4);
}

Часть HTML

 <body>
 <div id="images">
 </div>
 <canvas onmousemove="draw(event)" style="margin:0;padding:0;" id="imgCanvas"
          class="canvasView" width="250" height="250"></canvas> 

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

Ответ 1

Простой сценарий 1:1

В ситуациях, когда элемент canvas равен 1:1 по сравнению с размером растрового изображения, вы можете получить позиции мыши с помощью этого фрагмента:

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

Просто позвоните ему из своего события с событием и холстом в качестве аргументов. Он возвращает объект с x и y для позиций мыши.

Поскольку позиция мыши, которую вы получаете, относится к окну клиента, вам нужно будет вычесть позицию элемента canvas, чтобы преобразовать его относительно самого элемента.

Пример интеграции в ваш код:

//put this outside the event loop..
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");

function draw(evt) {
    var pos = getMousePos(canvas, evt);

    context.fillStyle = "#000000";
    context.fillRect (pos.x, pos.y, 4, 4);
}

Скрипка с изменениями

Примечание. Границы и отступы влияют на позицию, если они применяются непосредственно к элементу canvas, поэтому их нужно рассматривать с помощью getComputedStyle() - или применять эти стили к родительскому div вместо.

Когда элементы и растровые изображения имеют разные размеры

Если возникает ситуация, когда элемент имеет размер, отличный от самого растрового изображения, например, элемент масштабируется с использованием CSS или имеет соотношение сторон пикселей и т.д., вам придется решить эту проблему.

Пример:

function  getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect(), // abs. size of element
      scaleX = canvas.width / rect.width,    // relationship bitmap vs. element for X
      scaleY = canvas.height / rect.height;  // relationship bitmap vs. element for Y

  return {
    x: (evt.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
    y: (evt.clientY - rect.top) * scaleY     // been adjusted to be relative to element
  }
}

Скрипт с использованием шкалы

С преобразованиями, применяемыми к контексту (масштаб, поворот и т.д.)

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

Более новые браузеры позволяют читать текущую матрицу с помощью свойства currentTransform, а Firefox (текущая альфа) даже обеспечивают инвертированную матрицу через mozCurrentTransformInverted. Однако Firefox через mozCurrentTransform вернет массив, а не DOMMatrix, как он должен. Ни Chrome, если он включен с помощью экспериментальных флагов, вернет значение DOMMatrix, но SVGMatrix.

В большинстве случаев вам придется реализовать собственное собственное собственное матричное решение (например, мое собственное решение здесь - бесплатный проект /MIT ), пока это не получит полную поддержку.

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

Таким образом, точка будет в правильном положении относительно мыши. Также здесь вам нужно настроить координаты (перед применением обратной матрицы к ним) относительно элемента.

Пример, показывающий шаги матрицы

function draw(evt) {
    var pos = getMousePos(canvas, evt);        // get adjusted coordinates as above
    var imatrix = matrix.inverse();            // get inverted matrix somehow
    pos = imatrix.applyToPoint(pos.x, pos.y);  // apply to adjusted coordinate

    context.fillStyle = "#000000";
    context.fillRect(pos.x-1, pos.y-1, 2, 2);
}

Пример использования связанного выше решения (замените его с помощью встроенного браузера при более широком использовании).

Пример использования currentTransform при реализации:

    var pos = getMousePos(canvas, e);          // get adjusted coordinates as above
    var matrix = ctx.currentTransform;         // W3C (future)
    var imatrix = matrix.invertSelf();         // invert

    // apply to point:
    var x = pos.x * imatrix.a + pos.y * imatrix.c + imatrix.e;
    var y = pos.x * imatrix.b + pos.y * imatrix.d + imatrix.f;

Обновление Я сделал бесплатное решение (MIT), чтобы вставить все эти шаги в один простой в использовании объект, который можно найти здесь, а также позаботится о нескольких других nitty-gritty, которые большинство игнорирует.

Ответ 2

Вы можете получить позиции мыши с помощью этого фрагмента:

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
        y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
    };
}

Этот код учитывает как изменение координат в пространстве холста (evt.clientX - rect.left), так и масштабирование, когда размер логического холста отличается от его размера стилей (/ (rect.right - rect.left) * canvas.width см.: Ширина и высота холста в HTML5).

Пример: http://jsfiddle.net/sierawski/4xezb7nL/

Источник: jerryj комментировать http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

Ответ 3

Вам нужно получить положение мыши относительно холста

Для этого вам нужно знать положение X/Y холста на странице.

Это называется "смещением" canvass, и вот как получить смещение. (Я использую jQuery, чтобы упростить кросс-браузерную совместимость, но если вы хотите использовать необработанный javascript, то быстрый Google тоже получит это).

    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

Затем в обработчике мыши вы можете получить мышь X/Y следующим образом:

  function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
}

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

http://jsfiddle.net/m1erickson/WB7Zu/

<!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>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

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

    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;

    function handleMouseDown(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#downlog").html("Down: "+ mouseX + " / " + mouseY);

      // Put your mousedown stuff here

    }

    function handleMouseUp(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#uplog").html("Up: "+ mouseX + " / " + mouseY);

      // Put your mouseup stuff here
    }

    function handleMouseOut(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#outlog").html("Out: "+ mouseX + " / " + mouseY);

      // Put your mouseOut stuff here
    }

    function handleMouseMove(e){
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      $("#movelog").html("Move: "+ mouseX + " / " + mouseY);

      // Put your mousemove stuff here

    }

    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUp(e);});
    $("#canvas").mouseout(function(e){handleMouseOut(e);});

}); // end $(function(){});
</script>

</head>

<body>
    <p>Move, press and release the mouse</p>
    <p id="downlog">Down</p>
    <p id="movelog">Move</p>
    <p id="uplog">Up</p>
    <p id="outlog">Out</p>
    <canvas id="canvas" width=300 height=300></canvas>

</body>
</html>

Ответ 5

Вам не нужен javascript. Установите position:relative; в свой css для элемента canvas. Это намного более чистое кодирование, чем запуск script для постоянного исправления координат.