134

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

4

5 に答える 5

279

シンプルな 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 を持つオブジェクトを返します。

取得しているマウスの位置はクライアント ウィンドウに相対的であるため、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
  }
}

コンテキストに変換を適用 (スケール、回転など)

次に、回転、傾斜/せん断、スケール、平行移動などのコンテキストに変換を適用した、より複雑なケースがあります。これに対処するには、現在の行列の逆行列を計算できます。

新しいブラウザでは、プロパティを介して現在の行列を読み取ることができ、currentTransformFirefox (現在のアルファ版) では、mozCurrentTransformInverted. ただし、Firefox は、 を介しmozCurrentTransformて Array を返しますが、そうではありませんDOMMatrix。どちらの Chrome も、実験的なフラグを介して有効にすると、a を返します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) を作成しまし

于 2013-06-16T05:16:54.507 に答える
49

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

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 のコメント

于 2015-10-11T08:59:33.160 に答える
7

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

そのためには、ページ上のキャンバスの 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>
于 2013-06-16T05:56:01.627 に答える
3

この質問を参照してください:私が取得している mouseEvent.offsetX は、実際のキャンバス サイズよりもはるかに大きいです 。あなたの状況にぴったり合う関数をそこに与えました。

于 2013-06-16T10:09:22.853 に答える