캔버스를 사용하여 작은 그림 앱을 만들고 싶습니다. 캔버스에서 마우스의 위치를 찾아야합니다.
캔버스를 사용하여 작은 그림 앱을 만들고 싶습니다. 캔버스에서 마우스의 위치를 찾아야합니다.
답변:
JQuery를 사용하는 사람들의 경우 :
경우에 따라 이벤트가 첨부 된 중첩 요소가있는 경우 브라우저에서 상위 요소로 인식하는 내용을 이해하기 어려울 수 있습니다. 여기서 부모를 지정할 수 있습니다.
마우스 위치를 가져 와서 부모 요소의 오프셋 위치에서 빼십시오.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
스크롤 창 내 페이지에서 마우스 위치를 가져 오려는 경우 :
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
또는 페이지와 관련된 위치 :
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
다음 성능 최적화에 유의하십시오.
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
이런 식으로 JQuery는 #element
각 줄 을 찾을 필요가 없습니다 .
getBoundingClientRect ()를 지원하는 브라우저를 위해 아래 @anytimecoder의 최신 JavaScript 전용 버전이 있습니다 .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();
합니다.var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
복사 / 붙여 넣을 수있는 jQuery가없는 답변을 찾지 못 했으므로 여기에 사용 된 솔루션이 있습니다.
function clickEvent(e) {
// e = Mouse click event.
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left; //x position within the element.
var y = e.clientY - rect.top; //y position within the element.
}
e.currentTarget
e.target이 아닌 이 필요합니다 . 그렇지 않으면, 어린이 요소가 영향을 미칩니다
다음은 캔버스 요소에 대한 마우스 위치 관계를 계산합니다.
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
이 예에서 this
받는 지칭 example
요소와 e
는 IS onmousemove
이벤트.
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
this
에 e.currentTarget
당신이에 이벤트 리스너를 추가 한 요소의 위치를 얻을 것이다.
순수 자바 스크립트에는 참조 요소가 다른 위치에 중첩되어 절대 위치를 지정할 수있는 경우 상대 좌표를 반환하는 대답이 없습니다. 이 시나리오에 대한 해결책은 다음과 같습니다.
function getRelativeCoordinates (event, referenceElement) {
const position = {
x: event.pageX,
y: event.pageY
};
const offset = {
left: referenceElement.offsetLeft,
top: referenceElement.offsetTop
};
let reference = referenceElement.offsetParent;
while(reference){
offset.left += reference.offsetLeft;
offset.top += reference.offsetTop;
reference = reference.offsetParent;
}
return {
x: position.x - offset.left,
y: position.y - offset.top,
};
}
html
요소 오프셋
while(reference !== undefined)
으로 while(reference)
. Chrome에서는 적어도 offsetParent가로 끝나지 undefined
않고 null
. 그냥 여부를 확인 reference
truthy 그것이 모두 작동 보장 것이다 undefined
하고 null
.
offsetParent
다른 상황에서도 매우 유용한 것으로 판명 된 부동산 이 있다는 사실을 알려주므로 +1을 더 줄 것입니다 !
scrollLeft
하고 scrollTop
스크롤 후손을 보상 할 수 있습니다.
이 문제의 난이도에 대한 자세한 내용은 http://www.quirksmode.org/js/events_properties.html#position에서 확인할 수 있습니다 .
여기에 설명 된 기술을 사용하면 문서에서 마우스 위치를 찾을 수 있습니다. 그런 다음 요소의 경계 상자 안에 있는지 확인 element.getBoundingClientRect()
하면 다음 속성을 가진 객체를 반환하는 을 호출 하여 찾을 수 있습니다 { bottom, height, left, right, top, width }
. 거기에서 요소 내부 에서조차 발생했는지 여부를 알아내는 것은 사소한 일입니다.
나는이 모든 솔루션을 시도했으며 매트릭스 변환 컨테이너 (panzoom 라이브러리)를 사용한 특수 설정으로 인해 아무것도 작동하지 않았습니다. 확대 / 축소 및 이동 한 경우에도 올바른 값을 반환합니다.
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
그러나 방해 요소가없는 경우에만. CSS를 사용하여 이벤트에 '보이지 않게'만들어서 우회 할 수 있습니다.
.child {
pointer-events: none;
}
나는이 질문을 보았지만 내 경우 (DOM 요소 (내 경우에는 캔버스가 아님) 에서 드래그 를 사용 offsetX
하여) offsetY
에서 작동하도록하기 위해 드래그 마우스 이벤트 에서만 사용해야한다는 것을 알았습니다. .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
나는 올바른 방향으로 나를 얻었지만 Mark van Wyk의 대답을 +1하지만 나를 위해 그것을 해결하지 못했습니다. 나는 여전히 다른 요소에 포함 된 요소의 그림에 오프셋을 가졌습니다.
다음은 나를 위해 해결했습니다.
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
다시 말해서, 나는 단순히 중첩 된 모든 요소의 모든 오프셋을 쌓았습니다.
위의 답변 중 어느 것도 만족스러운 IMO가 아니므로 여기에 내가 사용하는 것이 있습니다.
// Cross-browser AddEventListener
function ael(e, n, h){
if( e.addEventListener ){
e.addEventListener(n, h, true);
}else{
e.attachEvent('on'+n, h);
}
}
var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW
if(touch){
ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}
// local mouse X,Y position in element
function showLocalPos(e){
document.title = (mx - e.getBoundingClientRect().left)
+ 'x'
+ Math.round(my - e.getBoundingClientRect().top);
}
그리고 페이지의 현재 Y 스크롤 위치를 알아야하는 경우 :
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
터치 스크린이있는 모바일 장치 및 / 또는 랩톱 / 모니터 용 일반 웹 사이트 또는 PWA (Progressive Web Apps)를 개발하는 사용자는 마우스 이벤트에 익숙 할 수 있고 때때로 고통스러운 Touch 경험에 익숙하지 않기 때문에 여기에 착륙했습니다. 이벤트 ... 예!
3 가지 규칙이 있습니다.
mousemove
또는 touchmove
행사 중에 가능한 한 적게하십시오 .mousedown
또는 touchstart
행사 중에 가능한 한 많이하십시오 .말할 것도없이, touch
이벤트 는 이벤트 가 더 복잡 할 수 있습니다. 하나 이상이있을 수 있고 마우스 이벤트보다 더 유연하고 복잡하기 때문입니다. 여기서는 한 번의 터치 만 다룰 것입니다. 예, 게으르고 있지만 가장 일반적인 유형의 터치입니다.
var posTop;
var posLeft;
function handleMouseDown(evt) {
var e = evt || window.event; // Because Firefox, etc.
posTop = e.target.offsetTop;
posLeft = e.target.offsetLeft;
e.target.style.background = "red";
// The statement above would be better handled by CSS
// but it's just an example of a generic visible indicator.
}
function handleMouseMove(evt) {
var e = evt || window.event;
var x = e.offsetX; // Wonderfully
var y = e.offsetY; // Simple!
e.target.innerHTML = "Mouse: " + x + ", " + y;
if (posTop)
e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop);
}
function handleMouseOut(evt) {
var e = evt || window.event;
e.target.innerHTML = "";
}
function handleMouseUp(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
}
function handleTouchStart(evt) {
var e = evt || window.event;
var rect = e.target.getBoundingClientRect();
posTop = rect.top;
posLeft = rect.left;
e.target.style.background = "green";
e.preventDefault(); // Unnecessary if using Vue.js
e.stopPropagation(); // Same deal here
}
function handleTouchMove(evt) {
var e = evt || window.event;
var pageX = e.touches[0].clientX; // Touches are page-relative
var pageY = e.touches[0].clientY; // not target-relative
var x = pageX - posLeft;
var y = pageY - posTop;
e.target.innerHTML = "Touch: " + x + ", " + y;
e.target.innerHTML += "<br>" + pageX + ", " + pageY;
e.preventDefault();
e.stopPropagation();
}
function handleTouchEnd(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
// Yes, I'm being lazy and doing the same as mouseout here
// but obviously you could do something different if needed.
e.preventDefault();
e.stopPropagation();
}
div {
background: yellow;
height: 100px;
left: 50px;
position: absolute;
top: 80px;
user-select: none; /* Disable text selection */
-ms-user-select: none;
width: 100px;
}
<div
onmousedown="handleMouseDown()"
onmousemove="handleMouseMove()"
onmouseout="handleMouseOut()"
onmouseup="handleMouseUp()"
ontouchstart="handleTouchStart()"
ontouchmove="handleTouchMove()"
ontouchend="handleTouchEnd()">
</div>
Move over box for coordinates relative to top left of box.<br>
Hold mouse down or touch to change color.<br>
Drag to turn on coordinates relative to top left of page.
Vue.js 를 선호 하십니까? 나는한다! 그런 다음 HTML은 다음과 같습니다.
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
당신은 그것을 얻을 수 있습니다
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
이 튜토리얼 에서 가져온 주석은 다음과 같이 수정되었습니다.
function getMousePos( canvas, evt ) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.floor( ( evt.clientX - rect.left ) / ( rect.right - rect.left ) * canvas.width ),
y: Math.floor( ( evt.clientY - rect.top ) / ( rect.bottom - rect.top ) * canvas.height )
};
}
다음과 같이 캔버스에서 사용하십시오.
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
나는 조금 늦었다는 것을 알고 있지만 이것은 PURE 자바 스크립트와 함께 작동하며 요소가 뷰포트보다 크고 사용자가 스크롤 한 경우 요소 내의 포인터 좌표를 제공합니다.
var element_offset_x ; // The distance from the left side of the element to the left of the content area
....// some code here (function declaration or element lookup )
element_offset_x = element.getBoundingClientRect().left - document.getElementsByTagName("html")[0].getBoundingClientRect().left ;
....// code here
function mouseMoveEvent(event)
{
var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ;
}
작동 방식
가장 먼저 할 일은 현재 뷰포트를 기준으로 HTML 요소 (컨텐츠 영역)의 위치를 얻는 것입니다. 페이지에 스크롤 막대가 있고 스크롤 된 getBoundingClientRect().left
경우 html 태그 에 대해 반환 된 숫자는 음수입니다. 그런 다음이 숫자를 사용하여 요소와 컨텐츠 영역의 왼쪽 사이의 거리를 계산합니다. 와element_offset_x = element.getBoundingClientRect().left......;
컨텐츠 영역에서 요소의 거리를 알고 있습니다. event.clientX
뷰포트에서 포인터의 거리를 알려줍니다. 뷰포트와 컨텐츠 영역이 서로 다른 두 엔티티라는 것을 이해하는 것이 중요합니다. 페이지가 스크롤되면 뷰포트가 이동할 수 있습니다. 따라서 clientX는 페이지가 스크롤 되더라도 동일한 번호를 반환합니다.
이를 보완하기 위해 포인터의 x 위치 (뷰포트 기준)를 뷰포트의 x 위치 (컨텐츠 영역 기준)에 추가해야합니다. 뷰포트의 X 위치는 window.pageXOffset.
@Spider의 솔루션을 기반으로 내 JQuery가 아닌 버전은 다음과 같습니다.
// Get the container element's bounding box
var sides = document.getElementById("container").getBoundingClientRect();
// Apply the mouse event listener
document.getElementById("canvas").onmousemove = (e) => {
// Here 'self' is simply the current window's context
var x = (e.clientX - sides.left) + self.pageXOffset;
var y = (e.clientY - sides.top) + self.pageYOffset;
}
이것은 스크롤과 줌 모두에서 작동합니다 (이 경우 때로는 수레를 반환합니다).
캔버스 내부의 마우스 좌표는 event.offsetX 및 event.offsetY 덕분에 얻을 수 있습니다. 내 요점을 증명하는 약간의 스 니펫이 있습니다.
c=document.getElementById("c");
ctx=c.getContext("2d");
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
c.addEventListener("mousemove",function(mouseEvt){
// the mouse's coordinates on the canvas are just below
x=mouseEvt.offsetX;
y=mouseEvt.offsetY;
// the following lines draw a red square around the mouse to prove it
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
ctx.fillStyle="red";
ctx.fillRect(x-5,y-5,10,10);
});
body {
background-color: blue;
}
canvas {
position: absolute;
top: 50px;
left: 100px;
}
<canvas id="c" width="100" height="100"></canvas>
canvas.onmousedown = function(e) {
pos_left = e.pageX - e.currentTarget.offsetLeft;
pos_top = e.pageY - e.currentTarget.offsetTop;
console.log(pos_left, pos_top)
}
HTMLElement.offsetLeft
HTMLElement.offsetLeft
판독 전용 속성 복귀 현재 요소의 상부 좌측 코너 내의 왼쪽으로 오프셋되는 화소의 수 HTMLElement.offsetParent
의 노드.
블록 레벨의 요소, offsetTop
, offsetLeft
, offsetWidth
, 및 offsetHeight
받는 소자 상대의 경계 박스를 설명 offsetParent
.
그러나, (예컨대 인라인 레벨 요소에 대한 span
하나의 행에서 다음으로 바꿈 수) offsetTop
및 offsetLeft
(처음 사용할 경계 박스의 위치를 설명 Element.getClientRects()
의 폭과 높이를 얻기 위해) 동안 offsetWidth
과 offsetHeight
경계 경계 박스의 크기를 설명하는 ( Element.getBoundingClientRect()
위치를 파악 하는 데 사용 ). 따라서, 왼쪽, 위쪽, 폭과 높이를 가진 박스 offsetLeft
, offsetTop
, offsetWidth
및 offsetHeight
래핑 된 텍스트와 범위에 대한 경계 박스 없습니다.
HTMLElement.offsetTop
HTMLElement.offsetTop
읽기 전용 속성의 상단에 현재 요소의 상대적 거리를 반환 offsetParent
노드를.
MouseEvent.pageX
pageX
읽기 전용 속성은 X (수평) 문서 전체를 기준으로하는, 이벤트의 상대 좌표를 픽셀 단위로 반환합니다. 이 속성은 페이지의 가로 스크롤을 고려합니다.
MouseEvent.pageY
MouseEvent.pageY
판독 전용 속성 복귀 Y (세로)는 전체 문서 이벤트의 상대 좌표를 픽셀 단위. 이 속성은 페이지의 세로 스크롤을 고려합니다.
자세한 설명은 Mozilla 개발자 네트워크를 참조하십시오.
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https : // developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
page
그리고 offset
나에게 매우 도움이 될 것입니다. 이 요청을 고려해 주셔서 감사합니다!
나는 매우 간단하다고 생각되는 다른 솔루션을 구현했기 때문에 여러분과 공유 할 것이라고 생각했습니다.
따라서 문제는 드래그 한 div가 마우스 커서에 대해 0,0 으로 점프한다는 것 입니다. 그래서 div의 새 위치를 조정하기 위해 div에서 마우스 위치를 캡처해야했습니다.
나는 div의 X 페이지와 페이지 Y를 읽고 상단을 설정하고 그에 따라 다음 값이 나는 onDragStart 리스너를 사용 사업부의 초기 위치에 커서를 유지하기 위해 좌표를 조정 얻고 저장하는 왼쪽 e.nativeEvent를 초기 트리거에서만 드래그 가능한 div 내에서 마우스 위치를 제공하는 .layerX 및 e.nativeEvent.layerY
예제 코드 :
onDrag={(e) => {
let newCoords;
newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
this.props.onDrag(newCoords, e, item.id);
}}
onDragStart={
(e) => {
this.setState({
correctionX: e.nativeEvent.layerX,
correctionY: e.nativeEvent.layerY,
});
}
나는 이것이 내가 겪었던 것과 같은 문제를 겪은 누군가를 도울 수 있기를 바랍니다. :)
캔버스가 div의 자식이고 다른 div의 자식 인 경우 이야기가 더 복잡해지기 때문에 페이지의 구조를 알아야합니다. 2 단계의 div 안에있는 캔버스에 대한 내 코드는 다음과 같습니다.
canvas.addEventListener("click", function(event) {
var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft);
var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop);
console.log("relative x=" + x, "relative y" + y);
});
원래 답변은 iframe에 넣었다고 말했습니다. 더 좋은 해결책은 패딩이 0px로 설정된 캔버스에서 이벤트 offsetX 및 offsetY를 사용하는 것입니다.
<html>
<body>
<script>
var main=document.createElement('canvas');
main.width="200";
main.height="300";
main.style="padding:0px;margin:30px;border:thick dashed red";
document.body.appendChild(main);
// adding event listener
main.addEventListener('mousemove',function(e){
var ctx=e.target.getContext('2d');
var c=Math.floor(Math.random()*0xFFFFFF);
c=c.toString(16); for(;c.length<6;) c='0'+c;
ctx.strokeStyle='#'+c;
ctx.beginPath();
ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI);
ctx.stroke();
e.target.title=e.offsetX+' '+e.offsetY;
});
// it worked! move mouse over window
</script>
</body>
</html>
당신은 사용할 수 getBoudingClientRect()
의 relative
부모입니다.
document.addEventListener("mousemove", (e) => {
let xCoord = e.clientX - e.target.getBoundingClientRect().left + e.offsetX
let yCoord = e.clientY - e.target.getBoundingClientRect().top + e.offsetY
console.log("xCoord", xCoord, "yCoord", yCoord)
})