クリックの x 座標と y 座標 (canvas 要素に対して) を返すクリック イベント ハンドラーを canvas 要素に追加する最も簡単な方法は何ですか?
従来のブラウザーとの互換性は必要ありません。Safari、Opera、および Firefox で十分です。
クリックの x 座標と y 座標 (canvas 要素に対して) を返すクリック イベント ハンドラーを canvas 要素に追加する最も簡単な方法は何ですか?
従来のブラウザーとの互換性は必要ありません。Safari、Opera、および Firefox で十分です。
シンプルさが好きで、クロスブラウザー機能が必要な場合は、このソリューションが最適であることがわかりました. これは @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)
})
更新(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;
編集 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;
私にとっては完全にうまくいきました。
新しいQuirksmodeによると、 メソッドclientX
とclientY
メソッドはすべての主要なブラウザでサポートされています。それで、ここに行きます-スクロールバーのあるページのスクロール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()
。
これは、幅が可変 (%) のキャンバスに対する 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}
}
親要素をループしてあらゆる種類の奇妙なことを行うこれらすべての回答のポイントが何であるかはわかりません。
この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) に対して機能します。
キャンバスの枠が太い場合は、少し複雑になります。文字通り、外接する四角形から境界線を差し引く必要があります。これは.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)
で置き換えます)。this
canvas
座標変換を行うときは注意してください。クリック イベントで複数の非クロス ブラウザー値が返されます。ブラウザ ウィンドウがスクロールされている場合、clientX と clientY を単独で使用するだけでは十分ではありません (Firefox 3.5 と Chrome 3.0 で検証済み)。
この quirks モードの記事では、pageX または pageY のいずれか、または clientX と document.body.scrollLeft および clientY と document.body.scrollTop の組み合わせを使用して、ドキュメントの原点に対するクリック座標を計算できる、より正確な関数を提供しています。
更新: さらに、offsetLeft と offsetTop は、内部のサイズではなく、要素のパディングされたサイズに相対的です。padding: スタイルが適用されたキャンバスは、そのコンテンツ領域の左上を offsetLeft として報告しません。この問題にはさまざまな解決策があります。最も簡単な方法は、キャンバス自体のすべてのボーダー、パディングなどのスタイルをクリアし、代わりにキャンバスを含むボックスに適用することです。
ここに非常に素晴らしいチュートリアルがあります-
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);
お役に立てれば!
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())
}
このリンクをお勧めします - 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>
プロトタイプでは、上記の Ryan Artecona が述べたように、cumulativeOffset() を使用して再帰的な合計を行います。
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 };
}
あなたはただ行うことができます:
var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;
これにより、マウス ポインターの正確な位置がわかります。
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;
多くの解決策を試した後。これは私にとってはうまくいきました。他の誰かを助けるかもしれないので、投稿してください。ここから入手
まず、他の人が言ったように、キャンバス要素の位置を取得する関数が必要です。これは、このページの他の方法よりも少しエレガントな方法です (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
あり、ラッパーノード (またはその他のもの) である可能性があります。をラップする要素がない場合、それらは に対して相対的であるため、減算するオフセットはありません。これが、他のことを行う前にキャンバスの位置を決定する必要がある理由です。offsetTop
offsetParent
div
canvas
body
同様にe.pageX
、e.pageY
ドキュメントに対するカーソルの位置を指定します。そのため、キャンバスのオフセットをこれらの値から差し引いて、真の位置に到達します。
配置された要素の代替手段は、e.layerX
との値を直接使用することですe.layerY
。これは、次の 2 つの理由から、上記の方法よりも信頼性が低くなります。
ねえ、これは dojo にあります。これは、私がプロジェクト用に既にコードを持っていたものだからです。
非 dojo バニラ JavaScript に変換する方法は明らかです。
function onMouseClick(e) {
var x = e.clientX;
var y = e.clientY;
}
var canvas = dojo.byId(canvasId);
dojo.connect(canvas,"click",onMouseClick);
それが役立つことを願っています。