308

クリックの x 座標と y 座標 (canvas 要素に対して) を返すクリック イベント ハンドラーを canvas 要素に追加する最も簡単な方法は何ですか?

従来のブラウザーとの互換性は必要ありません。Safari、Opera、および Firefox で十分です。

4

22 に答える 22

251

シンプルさが好きで、クロスブラウザー機能が必要な場合は、このソリューションが最適であることがわかりました. これは @Aldekein のソリューションを単純化したものですが、jQuery はありません

function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    console.log("x: " + x + " y: " + y)
}

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})
于 2013-08-05T08:26:06.513 に答える
180

更新(2016 年 5 月 5 日): patiques の回答は、よりシンプルで信頼性が高いため、代わりに使用する必要があります。


キャンバスは常にページ全体に対して相対的にスタイル設定されているわけではcanvas.offsetLeft/Topないため、常に必要なものが返されるとは限りません。スタイルが適用されdivたキャンバスを含む要素のようなものの場合がある、offsetParent 要素に相対的なオフセットのピクセル数を返します。これを考慮するには、canvas 要素自体から始めてposition: relative、一連の s をループする必要があります。offsetParentこのコードは私にとっては完全に機能し、Firefox と Safari でテストされていますが、すべての場合に機能するはずです。

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

最後の行は、キャンバス要素に対するマウス座標を取得するのに便利です。便利な座標を取得するために必要なのは、

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
于 2011-05-09T03:29:14.843 に答える
84

編集 2018:clientXこの回答はかなり古いものであり、現在のすべてのブラウザーでおよびclientYプロパティが機能するため、不要になった古いブラウザーのチェックを使用します。よりシンプルで最新のソリューションについては、Patriques Answerを確認してください。

元の回答:
当時見つけたが、もう存在しない記事に記載されているとおり:

var x;
var y;
if (e.pageX || e.pageY) { 
  x = e.pageX;
  y = e.pageY;
}
else { 
  x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
  y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

私にとっては完全にうまくいきました。

于 2010-12-13T15:38:09.077 に答える
19

新しいQuirksmodeによると、 メソッドclientXclientYメソッドはすべての主要なブラウザでサポートされています。それで、ここに行きます-スクロールバーのあるページのスクロールdivで機能する、うまく機能するコード:

function getCursorPosition(canvas, event) {
var x, y;

canoffset = $(canvas).offset();
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left);
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;

return [x,y];
}

これには、 jQuery forも必要です$(canvas).offset()

于 2011-03-24T10:44:40.823 に答える
12

これは、幅が可変 (%) のキャンバスに対する Ryan Artecona の回答に対する小さな変更です。

 HTMLCanvasElement.prototype.relMouseCoords = function (event) {
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do {
        totalOffsetX += currentElement.offsetLeft;
        totalOffsetY += currentElement.offsetTop;
    }
    while (currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    // Fix for variable canvas width
    canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );
    canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );

    return {x:canvasX, y:canvasY}
}
于 2012-04-01T02:21:49.793 に答える
7

親要素をループしてあらゆる種類の奇妙なことを行うこれらすべての回答のポイントが何であるかはわかりません。

このHTMLElement.getBoundingClientRectメソッドは、任意の要素の実際の画面位置を処理するように設計されています。これにはスクロールが含まれるため、次のようなものscrollTopは必要ありません。

(MDN から)ビューポート領域 (またはその他のスクロール可能な要素) で行われたスクロールの量は 、境界矩形を計算するときに考慮されます。

通常の画像

最も簡単なアプローチは、すでにここに投稿されています。ワイルドな CSSルールが含まれていない限り、これは正しいことです。

引き伸ばされたキャンバス/イメージの処理

画像のピクセル幅が CSS 幅と一致しない場合は、ピクセル値に比率を適用する必要があります。

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - left;
  y = event.clientY - top;
  //Also recalculate offsets of canvas is stretched
  var width = right - left;
  //I use this to reduce number of calculations for images that have normal size 
  if(this.width!=width) {
    var height = bottom - top;
    //changes coordinates by ratio
    x = x*(this.width/width);
    y = y*(this.height/height);
  } 
  //Return as an array
  return [x,y];
}

キャンバスに境界線がない限り、引き伸ばされた画像 (jsFiddle) に対して機能します。

CSS ボーダーの処理

キャンバスの枠が太い場合は、少し複雑になります。文字通り、外接する四角形から境界線を差し引く必要があります。これは.getComputedStyleを使用して実行できます。この回答はプロセスを説明しています

次に、関数は少し大きくなります。

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Subtract border size
  // Get computed style
  var styling=getComputedStyle(this,null);
  // Turn the border widths in integers
  var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
  var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
  var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
  var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
  //Subtract border from rectangle
  left+=leftBorder;
  right-=rightBorder;
  top+=topBorder;
  bottom-=bottomBorder;
  //Proceed as usual
  ...
}

この最終関数を混乱させるものは何も思いつきません。JsFiddleで自分自身を参照してください。

ノート

ネイティブの s を変更したくない場合はprototype、関数を変更して で呼び出します(anyを(canvas, event)で置き換えます)。thiscanvas

于 2014-11-29T17:27:08.020 に答える
7

座標変換を行うときは注意してください。クリック イベントで複数の非クロス ブラウザー値が返されます。ブラウザ ウィンドウがスクロールされている場合、clientX と clientY を単独で使用するだけでは十分ではありません (Firefox 3.5 と Chrome 3.0 で検証済み)。

この quirks モードの記事では、pageX または pageY のいずれか、または clientX と document.body.scrollLeft および clientY と document.body.scrollTop の組み合わせを使用して、ドキュメントの原点に対するクリック座標を計算できる、より正確な関数を提供しています。

更新: さらに、offsetLeft と offsetTop は、内部のサイズではなく、要素のパディングされたサイズに相対的です。padding: スタイルが適用されたキャンバスは、そのコンテンツ領域の左上を offsetLeft として報告しません。この問題にはさまざまな解決策があります。最も簡単な方法は、キャンバス自体のすべてのボーダー、パディングなどのスタイルをクリアし、代わりにキャンバスを含むボックスに適用することです。

于 2009-10-04T14:37:52.927 に答える
6

ここに非常に素晴らしいチュートリアルがあります-

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

 <canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  function writeMessage(canvas, message) {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.font = '18pt Calibri';
    context.fillStyle = 'black';
    context.fillText(message, 10, 25);
  }
  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');

  canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
    writeMessage(canvas, message);
  }, false);

お役に立てれば!

于 2013-07-01T10:10:30.950 に答える
3

2016 年に jQuery を使用して、キャンバスに対するクリック座標を取得するには、次のようにします。

$(canvas).click(function(jqEvent) {
    var coords = {
        x: jqEvent.pageX - $(canvas).offset().left,
        y: jqEvent.pageY - $(canvas).offset().top
    };
});

canvas offset() と jqEvent.pageX/Y の両方がスクロール位置に関係なくドキュメントに対して相対的であるため、これは機能します。

キャンバスがスケーリングされている場合、これらの座標はキャンバスの論理座標と同じではないことに注意してください。それらを取得するには、次のこと行います。

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}
于 2016-01-14T03:23:44.323 に答える
2

このリンクをお勧めします - http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html

<style type="text/css">

  #canvas{background-color: #000;}

</style>

<script type="text/javascript">

  document.addEventListener("DOMContentLoaded", init, false);

  function init()
  {
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousedown", getPosition, false);
  }

  function getPosition(event)
  {
    var x = new Number();
    var y = new Number();
    var canvas = document.getElementById("canvas");

    if (event.x != undefined && event.y != undefined)
    {
      x = event.x;
      y = event.y;
    }
    else // Firefox method to get the position
    {
      x = event.clientX + document.body.scrollLeft +
          document.documentElement.scrollLeft;
      y = event.clientY + document.body.scrollTop +
          document.documentElement.scrollTop;
    }

    x -= canvas.offsetLeft;
    y -= canvas.offsetTop;

    alert("x: " + x + "  y: " + y);
  }

</script>
于 2013-07-02T05:40:30.430 に答える
1

プロトタイプでは、上記の Ryan Artecona が述べたように、cumulativeOffset() を使用して再帰的な合計を行います。

http://www.prototypejs.org/api/element/cumulativeoffset

于 2011-07-26T23:10:13.073 に答える
1

http://jsbin.com/ApuJOSA/1/edit?html,outputでデモを参照してください。

  function mousePositionOnCanvas(e) {
      var el=e.target, c=el;
      var scaleX = c.width/c.offsetWidth || 1;
      var scaleY = c.height/c.offsetHeight || 1;

      if (!isNaN(e.offsetX)) 
          return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };

      var x=e.pageX, y=e.pageY;
      do {
        x -= el.offsetLeft;
        y -= el.offsetTop;
        el = el.offsetParent;
      } while (el);
      return { x: x*scaleX, y: y*scaleY };
  }
于 2013-12-01T08:05:03.927 に答える
1

あなたはただ行うことができます:

var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;

これにより、マウス ポインターの正確な位置がわかります。

于 2013-11-02T10:02:45.400 に答える
0

ThreeJS r77

var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;

mouse2D.x = ( x / renderer.domElement.width ) * 2 - 1;
mouse2D.y = - ( y / renderer.domElement.height ) * 2 + 1;

多くの解決策を試した後。これは私にとってはうまくいきました。他の誰かを助けるかもしれないので、投稿してください。ここから入手

于 2016-06-13T12:49:39.237 に答える
0

まず、他の人が言ったように、キャンバス要素の位置を取得する関数が必要です。これは、このページの他の方法よりも少しエレガントな方法です (IMHO)。任意の要素を渡して、ドキュメント内での位置を取得できます。

function findPos(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    return undefined;
}

それに対するカーソルの現在の位置を計算します。

$('#canvas').mousemove(function(e) {
    var pos = findPos(this);
    var x = e.pageX - pos.x;
    var y = e.pageY - pos.y;
    var coordinateDisplay = "x=" + x + ", y=" + y;
    writeCoordinateDisplay(coordinateDisplay);
});

findPos汎用関数をイベント処理コードから分離したことに注意してください。(そうあるべきです。関数をそれぞれ 1 つのタスクに保つようにする必要があります。)

との値は に対して相対的でoffsetLeftあり、ラッパーノード (またはその他のもの) である可能性があります。をラップする要素がない場合、それらは に対して相対的であるため、減算するオフセットはありません。これが、他のことを行う前にキャンバスの位置を決定する必要がある理由です。offsetTopoffsetParentdivcanvasbody

同様にe.pageXe.pageYドキュメントに対するカーソルの位置を指定します。そのため、キャンバスのオフセットをこれらの値から差し引いて、真の位置に到達します。

配置された要素の代替手段は、e.layerXとの値を直接使用することですe.layerY。これは、次の 2 つの理由から、上記の方法よりも信頼性が低くなります。

  1. これらの値は、イベントが配置された要素内で発生しない場合、ドキュメント全体に対しても相対的です。
  2. それらは標準の一部ではありません
于 2014-01-05T06:26:35.210 に答える
-1

ねえ、これは dojo にあります。これは、私がプロジェクト用に既にコードを持っていたものだからです。

非 dojo バニラ JavaScript に変換する方法は明らかです。

  function onMouseClick(e) {
      var x = e.clientX;
      var y = e.clientY;
  }
  var canvas = dojo.byId(canvasId);
  dojo.connect(canvas,"click",onMouseClick);

それが役立つことを願っています。

于 2008-09-11T02:49:27.190 に答える