web-dev-qa-db-ja.com

キャンバス内の実際のマウス位置

私は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で単純な関数を作成して正しい位置を取得する方法があることを読んだことがありますが、その方法についてはわかりません。

74

単純な1:1シナリオ

キャンバス要素がビットマップサイズと比較して1:1の状況では、このスニペットを使用してマウスの位置を取得できます。

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

イベントとキャンバスを引数としてイベントから呼び出すだけです。マウス位置のxとyを持つオブジェクトを返します。

取得するマウスの位置はクライアントウィンドウを基準にしているため、キャンバス要素の位置を減算して、要素自体を基準にして変換する必要があります。

コードへの統合の例:

//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に適用します。

要素とビットマップのサイズが異なる場合

たとえば、要素がビットマップ自体とは異なるサイズになっている場合、要素は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ではなくArrayを返します。どちらのChromeも、実験フラグで有効にした場合、DOMMatrixを返しますが、SVGMatrixを返します。

ただし、ほとんどの場合、完全にサポートされるまで、独自のカスタムマトリックスソリューション(独自のソリューション here -free/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;

Updateこれらのすべての手順を、見つけやすい単一の使いやすいオブジェクトに埋め込む無料ソリューション(MIT)を作成しました こちら また、ほとんど無視する他のいくつかの重要なことも処理します。

168
user1693593

このスニペットを使用して、マウスの位置を取得できます。

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/

出典: http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ に関するjerryjのコメント

24
Rafał S

キャンバスに対するマウスの位置を取得する必要があります

そのためには、ページ上のキャンバスの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>
5
markE

キャンバスイベントで正しいマウスクリックまたはマウス移動位置を計算する最も簡単な方法は、次の小さな式を使用することです。

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-leftまたはpadding-topがある場合、以下を介してxとyを減算します。

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

3
Martin Wantke
3
sumitb.mdi