簡體   English   中英

canvas中的真鼠標position

[英]Real mouse position in canvas

I'm trying to draw with the mouse over a HTML5 canvas, but the only way that it seems to work well is if the canvas is in the position 0,0 (upper left corner) if I change the canvas position, for some reason它不像它應該畫的那樣。 這是我的代碼。

 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 中創建一個簡單的 function 以獲得正確的 position,但我不知道該怎么做。

簡單的 1:1 場景

對於畫布元素與位圖大小為 1:1 的情況,您可以使用以下代碼段獲取鼠標位置:

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

只需使用事件和畫布作為參數從您的事件中調用它。 它返回一個帶有xy鼠標位置的對象。

由於您獲得的鼠標位置是相對於客戶端窗口的,因此您必須減去畫布元素的位置才能將其相對於元素本身進行轉換。

代碼中的集成示例:

// 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);
}

注意:如果直接應用於畫布元素,邊框和填充將影響位置,因此需要通過getComputedStyle()考慮這些 - 或者將這些樣式應用於父 div。

當 Element 和 Bitmap 大小不同時

當元素的大小與位圖本身不同時,例如,使用 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(當前 alpha)甚至通過mozCurrentTransformInverted提供倒置矩陣。 然而,Firefox 通過mozCurrentTransform將返回一個 Array 而不是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),將所有這些步驟嵌入到一個易於使用的對象中,該對象可以在此處找到,並且還處理了一些大多數人忽略的其他細節問題。

您可以使用以下代碼段獲取鼠標位置:

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
    };
}

This code takes into account both changing coordinates to canvas space ( evt.clientX - rect.left ) and scaling when canvas logical size differs from its style size ( / (rect.right - rect.left) * canvas.width see: Canvas width和 HTML5 中的高度)。

示例:http: //jsfiddle.net/sierawski/4xezb7nL/

資料來源:jerryj 對http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/的評論

您需要獲取相對於畫布的鼠標位置

為此,您需要知道畫布在頁面上的 X/Y 位置。

這被稱為畫布的“偏移量”,這里是如何獲得偏移量。 (我使用 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>

在畫布事件上計算正確的鼠標單擊或鼠標移動位置的最簡單方法是使用這個小等式:

canvas.addEventListener('click', event =>
{
    let bound = canvas.getBoundingClientRect();

    let x = event.clientX - bound.left - canvas.clientLeft;
    let y = event.clientY - bound.top - canvas.clientTop;

    context.fillRect(x, y, 16, 16);
});

如果畫布有padding-leftpadding-top ,請通過以下方式減去 x 和 y:

x -= parseFloat(style['padding-left'].replace('px'));
y -= parseFloat(style['padding-top'].replace('px'));

參考這個問題: 我得到的 mouseEvent.offsetX 比實際畫布尺寸大得多。我在那里給出了一個完全適合你情況的函數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM