캔버스 요소에서 마우스 클릭의 좌표를 얻으려면 어떻게해야합니까?


276

클릭 이벤트 핸들러를 캔버스 요소에 추가하여 클릭의 x 및 y 좌표를 반환하는 가장 간단한 방법은 무엇입니까 (캔버스 요소 기준)?

레거시 브라우저 호환성이 필요하지 않으며 Safari, Opera 및 Firefox가 지원합니다.


이것은 일반적인 dom 요소에서 마우스 이벤트를 얻는 것과 다르지 않아야합니다. quirksmode그것에 대한 좋은 참조가 있습니다.
airportyh

4
위에 나열된 코드는 캔버스가 다른 컨테이너 내부에 있지 않은 경우에만 작동합니다. 일반적으로 jquery 오프셋 함수와 같은 것을 사용해야합니다. [var testDiv = $ ( '# testDiv'); 크로스 브라우저 방식으로 올바른 오프셋을 얻으려면 var offset = testDiv.offset ();]. 이것은 ***의 진정한 고통입니다.
Aaron Watters

캔버스가 포함 된 페이지가 스크롤되면 위에서 Update로 게시 된 코드가 작동하지 않습니다.
Timothy Kim

질문에 대한 업데이트로 포함 된 이전 "응답"을 제거했습니다. 언급했듯이, 구식이며 불완전했습니다.
Tom

3
여기에 50 개의 답변이 있으므로이 녀석 답변으로 스크롤하는 것이 좋습니다 : patriques-좋고 간단한 5 라이너.
Igor L.

답변:


77

2018 편집 : 이 답변은 꽤 오래되었으며 더 이상 필요하지 않은 이전 브라우저에 대한 검사를 사용합니다. clientXclientY현재 속성은 모든 현재 브라우저에서 작동합니다. 더 간단하고 최신 솔루션에 대해서는 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;

나를 위해 완벽하게 일했습니다.


30
이 솔루션은 항상 작동하지는 않습니다. Ryan Artecona의 답변은 캔버스가 전체 페이지를 기준으로 배치 될 필요가없는보다 일반적인 경우에 작동합니다.
Chris Johnson

3
클릭 / 이동마다 Dom 액세스가 수행되므로 성능이 중요한 경우에는이 솔루션이 적합하지 않습니다. 그리고 getBoundingClientRect는 현재 존재하며 더 우아합니다.
GameAlchemist

192

단순성을 좋아하지만 여전히 브라우저 간 기능을 원한다면이 솔루션이 가장 효과적이라는 것을 알았습니다. 이것은 @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)
})

페이지가 아래로 스크롤되면 문서의 스크롤 오프셋도 고려해야한다고 생각합니다.
Peppe LG

8
@ PeppeL-G 바운딩 클라이언트 사각형이이를 계산합니다. 의견을 게시하기 전에 콘솔에서 쉽게 테스트 할 수 있습니다 (그렇습니다).
Tomáš Zato-복원 모니카

1
@ TomášZato, 오, getBoundingClientRect뷰 포트에 상대적인 위치를 반환합니까? 그런 다음 내 추측은 틀렸다. 나는 이것이 결코 문제가되지 않았기 때문에 그것을 테스트하지 않았으며, 다른 독자들에게 내가 본 잠재적 문제에 대해 친절하게 경고하고 싶었지만 명확하게 해 주셔서 감사합니다.
Peppe LG

1
캔버스의 크기가 조정되면 작동하지 않습니다. 브라우저 버그인지 확실하지 않습니다.
Jeroen

2
나와 같은 사람을위한 사용법 추가 :var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion

179

업데이트 (5/5/16) : 더 간단하고 신뢰할 수 있기 때문에 patriques의 답변 을 대신 사용해야합니다.


캔버스는 항상 전체 페이지를 기준으로 스타일이 지정 canvas.offsetLeft/Top되지 않으므로 필요한 것을 항상 반환하지는 않습니다. 스타일이 적용된 div캔버스를 포함 하는 요소 와 같은 offsetParent 요소를 기준으로 오프셋 된 픽셀 수를 반환합니다 position: relative. 이를 설명하려면 offsetParentcanvas 요소 자체부터 시작 하여 체인을 반복해야 합니다. 이 코드는 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;

8
아니요, 내장 자바 스크립트 프로토 타입 객체를 사용하고 있습니다. --- developer.mozilla.org/en/…
garg

14
내 크롬이 event.offsetXevent.offsetY속성은, 그래서 추가하여 솔루션을 수정 if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. 작동하는 것 같습니다.
Baczek

3
Baczek 크롬의 약 정확 event.offsetX하고 event.offsetY또한 IE9에서 작동한다. Firefox (v13에서 테스트)의 경우 event.layerX및 을 사용할 수 있습니다 event.layerY.
mafafu

3
나는 이것을 추가로 추가했다 : canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc

4
이 최종 답변은 작동하지 않았습니다. Firefox에서 전체 화면이 스크롤되면 변위 된 값이 출력으로 나타납니다. 나를 위해 일한 것은 event.pageX / Y 대신에 event.clientX / Y에서 계산 된 오프셋을 뺀 stackoverflow.com/a/10816667/578749에 제공된 매우 유사한 솔루션 이었습니다. 누군가 이것을 검토하고 설명 할 수 있습니까?
lvella

33

최신 브라우저가 이제이를 처리합니다. Chrome, IE9 및 Firefox는 이와 같은 오프셋 X / Y를 지원하여 클릭 핸들러에서 이벤트를 전달합니다.

function getRelativeCoords(event) {
    return { x: event.offsetX, y: event.offsetY };
}

대부분의 최신 브라우저는 layerX / Y도 지원하지만 Chrome과 IE는 마진, 패딩 등 페이지 클릭의 절대 오프셋에 layerX / Y를 사용합니다. Firefox에서는 layerX / Y와 offsetX / Y는 동일하지만 오프셋은 이전에는 존재하지 않았습니다. 따라서 약간 오래된 브라우저와의 호환성을 위해 다음을 사용할 수 있습니다.

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}

1
layerX, layerY가 Chrome과 Firefox 모두에서 정의되는 방식에 흥미가 있지만 Chrome에서는 정확하지 않습니다 (또는 다른 것을 의미합니다).
Julian Mann

@JulianMann 정보를 주셔서 감사합니다. 최신 지원을 기반으로이 답변을 업데이트했습니다. 이제 거의 보편적으로 offsetX / Y로 벗어날 수있을 것 같습니다.
mafafu

18

신선한에 따르면 쿼크 모드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 가 필요 합니다 $(canvas).offset().


@ N4ppeL 답변과 같습니다.
Paweł Szczur


11

너비 (%)가 가변 인 캔버스에 대한 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}
}

7

좌표 변환을 수행하는 동안 조심하십시오. click 이벤트에서 여러 비 브라우저 간 값이 반환됩니다. 브라우저 창이 스크롤되면 (Firefox 3.5 및 Chrome 3.0에서 확인 된 경우) clientX와 clientY 만 사용하는 것만으로는 충분하지 않습니다.

이 쿼크 모드 아티클은 pageX 또는 pageY 또는 clientX와 document.body.scrollLeft를 사용하고 clientY를 document.body.scrollTop과 함께 사용하여 문서 원점을 기준으로 클릭 좌표를 계산할 수있는보다 정확한 기능을 제공합니다.

업데이트 : 또한 offsetLeft 및 offsetTop은 내부 크기가 아닌 요소의 채워진 크기를 기준으로합니다. 패딩 : 스타일이 적용된 캔버스는 컨텐츠 영역의 왼쪽 상단을 offsetLeft로보고하지 않습니다. 이 문제에 대한 다양한 해결책이 있습니다. 가장 간단한 방법은 캔버스 자체의 모든 테두리, 패딩 등 스타일을 지우고 대신 캔버스를 포함하는 상자에 적용하는 것입니다.


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 에서 자신을 참조하십시오 .

노트

네이티브 수정처럼하지 않으면 prototype들, 바로 기능을 변경하고 그것을 호출 (canvas, event)(및 교체 this로를 canvas).


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

도움이 되었기를 바랍니다!


Ryan Artecona의 솔루션은 확대 / 축소 기능이있는 태블릿 브라우저에서 작동하지 않았습니다. 그러나 이것은했다.
Andy Meyers

CSS width/ heightoverride가 있지만 여전히 최고의 솔루션 중 하나 인 이미지에서는 작동하지 않습니다 .
Tomáš Zato-복원 모니카

3

2016 년 jQuery를 사용하여 캔버스를 기준으로 클릭 좌표를 얻으려면 다음을 수행하십시오.

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

이것은 캔버스 오프셋 ()과 jqEvent.pageX / Y가 스크롤 위치에 관계없이 문서에 상대적이기 때문에 작동합니다.

캔버스의 크기가 조정 된 경우 이러한 좌표는 캔버스 논리 좌표 와 동일하지 않습니다 . 사람들을 얻으려면, 당신은 것 또한 수행

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}

와. 'jqEvent'는 어떻게 정의됩니까? 아니면 '캔버스'? 아니면 두 번째 예인 'coords'? 두 번째 예제 전에 첫 번째 예제를 실행해야합니까? 그렇다면 왜 "그것을 얻기 위해"라고 쓰지 않겠습니까? 이 모든 기능이 온 클릭 기능에 포함됩니까? 약간의 맥락을 알려주십시오. 그리고 2008 년에 처음 제기 된 질문을 고려할 때 2008 년에 사용 가능한 기술과 관련하여 답변해야한다고 생각합니다. 당시 사용 가능한 버전 (v1.2)의 유효한 jQuery를 사용하여 답변을 구체화하십시오. ;)
Ayelis

1
알 겠어, 내 생각에 미안해 나는 그것을 제거하기 위해 편집 할 것입니다. 가장 최근의 프레임 워크를 사용하여 답변을 제공하려고했습니다. 그리고 나는 프로그래머가 jqEvent, canvas 및 coords가 무엇인지 설명 할 필요가 없다고 생각합니다.
Sarsaparilla

좋아 보인다 입력 해 주셔서 감사합니다! 힘들게해서 미안 해요! ;)
Ayelis

3

그래서 이것은 단순하지만 다소 복잡한 주제입니다.

우선 여기에는 일반적으로 복잡한 질문이 있습니다.

  1. 요소 관련 마우스 좌표를 얻는 방법

  2. 2D Canvas API 또는 WebGL에 대한 캔버스 픽셀 마우스 좌표를 얻는 방법

그래서 대답

요소 관련 마우스 좌표를 얻는 방법

요소가 요소 상대 마우스 좌표를 얻는 캔버스인지 여부는 모든 요소에서 동일합니다.

"캔버스 관련 마우스 좌표를 얻는 방법"이라는 질문에 대한 두 가지 간단한 답변이 있습니다.

간단한 답변 # 1 사용 offsetXoffsetY

canvas.addEventListner('mousemove', (e) => {
  const x = e.offsetX;
  const y = e.offsetY;
});

이 답변은 Chrome, Firefox 및 Safari에서 작동합니다. 다른 모든 이벤트 값 offsetX과 달리offsetY CSS 변환을 고려하십시오.

가장 큰 문제 offsetXoffsetY그들이 터치 이벤트에 존재하지 않는 등 iOS의 사파리와 함께 사용할 수 없습니다 2019/05의로이다. 그것들은 Chrome과 Firefox에는 존재하지만 Safari는 분명히 작동 하지만 Safari는 아닌 Pointer Events에 존재 합니다. .

또 다른 문제는 이벤트가 캔버스 자체에 있어야한다는 것입니다. 다른 요소 나 창에 놓으면 나중에 참조 지점으로 캔버스를 선택할 수 없습니다.

간단한 대답 # 2 사용 clientX, clientYcanvas.getBoundingClientRect

당신이 CSS의 변환에 대해 걱정하지 않는 경우 다음 간단한 대답은 호출하는 것입니다 canvas. getBoundingClientRect()및 빼기으로부터 왼쪽 clientXtop에서 clientY와 같이

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
});

CSS 변환이없는 한 작동합니다. 터치 이벤트에서도 작동하므로 Safari iOS에서도 작동합니다.

canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});

2D Canvas API에 대한 캔버스 픽셀 마우스 좌표를 얻는 방법

이를 위해 우리는 위에서 얻은 값을 가져 와서 캔버스가 표시되는 크기에서 캔버스 자체의 픽셀 수로 변환해야합니다

canvas.getBoundingClientRectclientXclientY

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const elementRelativeX = e.clientX - rect.left;
  const elementRelativeY = e.clientY - rect.top;
  const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
  const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});

이나와 offsetXoffsetY

canvas.addEventListener('mousemove', (e) => {
  const elementRelativeX = e.offsetX;
  const elementRelativeX = e.offsetY;
  const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
  const canvasRelativeY = elementRelativeX * canvas.height / canvas.clientHeight;
});

노트 : 모든 경우에 캔버스에 패딩 또는 테두리를 추가하지 마십시오. 그렇게하면 코드가 엄청나게 복잡해집니다. 대신 다른 요소에서 캔버스를 둘러싸는 테두리 또는 패딩을 원하고 외부 요소에 패딩 및 / 또는 테두리를 추가하십시오.

를 사용하는 실제 예 event.offsetX,event.offsetY

사용 예 작업 canvas.getBoundingClientRectevent.clientXevent.clientY


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>

요점은 x = new Number()무엇입니까? 할당 x된 숫자가 즉시 폐기됨을 의미하는 아래 코드는 다시 할당됩니다
gman


1

당신은 할 수 있습니다 :

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

마우스 포인터의 정확한 위치를 알려줍니다.


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

0

위의 Ryan Artecona 솔루션의 일부 수정 사항이 있습니다.

function myGetPxStyle(e,p)
{
    var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";
    return parseFloat(r);
}

function myGetClick=function(ev)
{
    // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27
    // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21
    // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad
    // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)
    // html.offsetX and html.offsetY don't work with mac firefox 21

    var offsetX=0,offsetY=0,e=this,x,y;
    var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);

    do
    {
        offsetX+=e.offsetLeft-e.scrollLeft;
        offsetY+=e.offsetTop-e.scrollTop;
    } while (e=e.offsetParent);

    if (html)
    {
        offsetX+=myGetPxStyle(html,"marginLeft");
        offsetY+=myGetPxStyle(html,"marginTop");
    }

    x=ev.pageX-offsetX-document.body.scrollLeft;
    y=ev.pageY-offsetY-document.body.scrollTop;
    return {x:x,y:y};
}

0

먼저 다른 사람들이 말했듯 이 canvas 요소위치 를 가져 오는 함수가 필요합니다 . 이 페이지의 다른 것보다 조금 더 우아한 방법 (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이벤트 처리 코드에서 일반 함수를 분리했습니다 . ( 그대로 . 우리는 각각 하나의 작업에 기능을 유지하려고 노력해야합니다.)

offsetLeft및 의 값 offsetTop은와 관련되며 offsetParent, 이는 랩퍼 div노드 (또는 그 문제에 대한 다른 것) 일 수 있습니다 . 줄 바꿈하는 요소가 없으면을 canvas기준으로 body하므로 빼기위한 오프셋이 없습니다. 그렇기 때문에 다른 작업을하기 전에 캔버스의 위치를 ​​결정해야합니다.

Similary, e.pageXe.pageY 문서에 커서의 위치를 제공합니다. 그렇기 때문에 우리는 그 값에서 캔버스의 오프셋을 빼서 실제 위치에 도달합니다.

위치 지정된 요소 의 대안 은 e.layerX및 의 값을 직접 사용하는 것입니다 e.layerY. 두 가지 이유로 위의 방법보다 안정성이 떨어집니다.

  1. 이러한 값은 이벤트가 위치 지정된 요소 내에서 발생하지 않을 때 전체 문서와 관련이 있습니다.
  2. 그들은 표준의 일부가 아닙니다

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;

많은 솔루션을 시도한 후. 이것은 나를 위해 일했습니다. 다른 사람이 게시하도록 도울 수 있습니다. 여기서 부터


0

다음은 단순화 된 솔루션입니다 (테두리 / 스크롤에서는 작동하지 않음).

function click(event) {
    const bound = event.target.getBoundingClientRect();

    const xMult = bound.width / can.width;
    const yMult = bound.height / can.height;

    return {
        x: Math.floor(event.offsetX / xMult),
        y: Math.floor(event.offsetY / yMult),
    };
}

0

PDF 확대 / 축소와 같은 많은 캔버스 크기 조정과 관련된 pdf 위에 캔버스가 있는 응용 프로그램을 만들고 있었고 PDF 확대 / 축소를 켜기 위해 캔버스 크기를 조정해야했습니다. pdf의 크기, 나는 stackOverflow에서 많은 답변을 받았고 결국 문제를 해결할 완벽한 솔루션을 찾지 못했습니다.

나는 rxjs 와 angular 6 을 사용하고 있었고 최신 버전에 대한 답변을 찾지 못했습니다.

다음은 rxjs 를 사용하여 캔버스 위에 그리는 사람에게 도움이 될 전체 코드 스 니펫입니다 .

  private captureEvents(canvasEl: HTMLCanvasElement) {

    this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
      .pipe(
        switchMap((e: any) => {

          return fromEvent(canvasEl, 'mousemove')
            .pipe(
              takeUntil(fromEvent(canvasEl, 'mouseup').do((event: WheelEvent) => {
                const prevPos = {
                  x: null,
                  y: null
                };
              })),

              takeUntil(fromEvent(canvasEl, 'mouseleave')),
              pairwise()
            )
        })
      )
      .subscribe((res: [MouseEvent, MouseEvent]) => {
        const rect = this.cx.canvas.getBoundingClientRect();
        const prevPos = {
          x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };
        const currentPos = {
          x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };

        this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
        this.drawOnCanvas(prevPos, currentPos);
      });
  }

캔버스를 확대 / 축소하는 방법에 관계없이 캔버스 크기를 기준으로 마우스 좌표를 수정하는 스 니펫이 있습니다.

const prevPos = {
  x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
  x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};

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

희망이 도움이됩니다.


6
clientX / clientY는 브라우저에서 유사하게 작동하지 않습니다.
tfwright
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.