Tôi muốn làm một ứng dụng vẽ tranh nhỏ bằng vải. Vì vậy, tôi cần tìm vị trí của chuột trên khung vẽ.
Tôi muốn làm một ứng dụng vẽ tranh nhỏ bằng vải. Vì vậy, tôi cần tìm vị trí của chuột trên khung vẽ.
Câu trả lời:
Đối với những người sử dụng JQuery:
Đôi khi, khi bạn có các phần tử lồng nhau, một trong số chúng có sự kiện được đính kèm, có thể khó hiểu khi trình duyệt của bạn xem là phần tử mẹ. Ở đây, bạn có thể chỉ định cha mẹ.
Bạn lấy vị trí chuột và sau đó trừ nó khỏi vị trí bù của phần tử cha.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
Nếu bạn đang cố lấy vị trí chuột trên một trang bên trong ngăn cuộn:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
Hoặc vị trí liên quan đến trang:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Lưu ý tối ưu hóa hiệu suất sau:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
Theo cách này, JQuery không phải tìm kiếm #element từng dòng.
Có một phiên bản mới hơn, chỉ có JavaScript bên dưới bởi @anytimecoder bên dưới dành cho các trình duyệt hỗ trợ getBoundingClientRect () .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();thànhvar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Vì tôi không tìm thấy câu trả lời không có jQuery mà tôi có thể sao chép / dán, đây là giải pháp tôi đã sử dụng:
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, không phải e.target. Nếu không, các yếu tố trẻ em sẽ ảnh hưởng đến nó
Sau đây tính toán mối quan hệ vị trí chuột với phần tử canvas:
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
Trong ví dụ này, thisđề cập đến examplephần tử và elà onmousemovesự kiện.
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
thistới e.currentTarget, mà sẽ giúp bạn có được vị trí tương đối so với các yếu tố mà bạn thêm người nghe sự kiện vào.
Không có câu trả lời trong javascript thuần trả về tọa độ tương đối khi phần tử tham chiếu được lồng bên trong các phần tử khác có thể được định vị tuyệt đối. Đây là một giải pháp cho kịch bản này:
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,
};
}
htmlyếu tố bù trừ
while(reference !== undefined)bằng while(reference). Trong Chrome ít nhất, offsetParent cuối cùng không tồn tại undefined, nhưng null. Chỉ cần kiểm tra xem sự referencethật có đảm bảo nó hoạt động với cả hai undefinedvà null.
offsetParenttài sản, hóa ra nó cũng rất hữu ích trong các tình huống khác!
scrollLeftvà scrollTopđể bù đắp cho con cháu di chuyển.
Một bài viết hay về khó khăn của vấn đề này có thể được tìm thấy ở đây: http://www.quirksmode.org/js/events_properIES.html#poseition
Sử dụng kỹ thuật được mô tả ở đó, bạn có thể tìm thấy vị trí chuột trong tài liệu. Sau đó, bạn chỉ cần kiểm tra xem nó có nằm trong hộp giới hạn của phần tử của bạn hay không, bằng cách gọi element.getBoundingClientRect()nó sẽ trả về một đối tượng có các thuộc tính sau : { bottom, height, left, right, top, width }. Từ đó, thật tầm thường để biết liệu thậm chí có xảy ra bên trong yếu tố của bạn hay không.
Tôi đã thử tất cả các giải pháp này và do thiết lập đặc biệt của tôi với một thùng chứa biến đổi ma trận (thư viện panzoom) không có hiệu quả. Điều này trả về giá trị chính xác, ngay cả khi phóng to và xoay:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
Nhưng chỉ khi không có yếu tố con theo cách này. Điều này có thể được phá vỡ bằng cách làm cho chúng 'vô hình' đối với sự kiện, sử dụng CSS:
.child {
pointer-events: none;
}
Tôi đã gặp câu hỏi này, nhưng để làm cho nó hoạt động cho trường hợp của tôi (sử dụng tính năng kéo trên phần tử DOM (không phải là canvas trong trường hợp của tôi)), tôi thấy rằng bạn chỉ phải sử dụng offsetXvà offsetYtrong sự kiện kéo chuột .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
Tôi +1 'Câu trả lời của Mark van Wyk vì nó đã đưa tôi đi đúng hướng, nhưng không giải quyết được cho tôi. Tôi vẫn có một khoảng trống trên bức tranh trong các yếu tố chứa trong một yếu tố khác.
FOllowing đã giải quyết nó cho tôi:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
Nói cách khác - tôi chỉ đơn giản xếp chồng tất cả các phần bù từ tất cả các phần tử lồng nhau
Không có câu trả lời nào ở trên là IMO thỏa đáng, vì vậy đây là những gì tôi sử dụng:
// 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);
}
Và nếu bạn cần biết vị trí cuộn Y hiện tại của trang:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
Đối với những người bạn đang phát triển trang web thông thường hoặc PWAs (Ứng dụng web lũy tiến) cho thiết bị di động và / hoặc máy tính xách tay / màn hình có màn hình cảm ứng, thì bạn đã đến đây vì bạn có thể quen với các sự kiện chuột và mới đối với trải nghiệm đôi khi đau đớn của Touch sự kiện ... yay!
Chỉ có 3 quy tắc:
mousemovehoặc touchmovesự kiện.mousedownhoặc touchstartsự kiện.Không cần phải nói, mọi thứ phức tạp hơn với touchcác sự kiện vì có thể có nhiều hơn một và chúng linh hoạt (phức tạp) hơn các sự kiện chuột. Tôi sẽ chỉ bao gồm một liên lạc duy nhất ở đây. Vâng, tôi đang lười biếng, nhưng đó là loại cảm ứng phổ biến nhất, vì vậy có.
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.
Thích sử dụng Vue.js ? Tôi làm! Sau đó, HTML của bạn sẽ trông như thế này:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
bạn có thể lấy nó bằng cách
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
Lấy từ hướng dẫn này , với các chỉnh sửa được thực hiện nhờ vào nhận xét hàng đầu:
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 )
};
}
Sử dụng trên một khung vẽ như sau:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
Tôi nhận ra mình hơi muộn, nhưng điều này hoạt động với javascript PURE và thậm chí nó còn cung cấp cho bạn tọa độ của con trỏ trong phần tử nếu phần tử lớn hơn chế độ xem và người dùng đã cuộn.
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 ;
}
Làm thế nào nó hoạt động.
Điều đầu tiên chúng ta làm là lấy vị trí của phần tử HTML (vùng nội dung) so với chế độ xem hiện tại. Nếu trang có thanh cuộn và được cuộn, thì số được trả về bởigetBoundingClientRect().left cho thẻ html sẽ âm. Sau đó chúng tôi sử dụng số này để tính khoảng cách giữa phần tử và bên trái của khu vực nội dung. Vớielement_offset_x = element.getBoundingClientRect().left......;
Biết khoảng cách của phần tử từ khu vực nội dung. event.clientXcho chúng ta khoảng cách của con trỏ từ khung nhìn. Điều quan trọng là phải hiểu rằng chế độ xem và khu vực nội dung là hai thực thể khác nhau, chế độ xem có thể di chuyển nếu trang được cuộn. Do đó, clientX sẽ trả về số CÙNG ngay cả khi trang được cuộn.
Để bù cho điều này, chúng ta cần thêm vị trí x của con trỏ (liên quan đến chế độ xem), vào vị trí x của chế độ xem (liên quan đến khu vực nội dung). Vị trí X của khung nhìn được tìm thấy với window.pageXOffset.
Dựa trên giải pháp của @ Spider, phiên bản không phải JQuery của tôi là:
// 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;
}
Điều này hoạt động cả với cuộn và phóng to (trong trường hợp này đôi khi nó trả về số float).
Các tọa độ chuột bên trong một khung vẽ có thể thu được nhờ event.offsetX và event.offsetY. Đây là một đoạn nhỏ để chứng minh quan điểm của tôi:
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)
}
HTMLEuity.offsetLeft
Các HTMLElement.offsetLeftlợi nhuận thuộc tính chỉ đọc số lượng điểm ảnh góc trên bên trái của phần tử hiện nay được bù đắp bên trái trongHTMLElement.offsetParent nút.
Đối với yếu tố khối cấp, offsetTop, offsetLeft, offsetWidth, và offsetHeightmô tả các hộp biên giới của một phần tử tương đối so với offsetParent.
Tuy nhiên, đối với các phần tử mức nội tuyến (chẳng hạn span) có thể bao bọc từ dòng này sang dòng tiếp theo offsetTopvà offsetLeftmô tả vị trí của hộp viền đầu tiên (sử dụng Element.getClientRects()để lấy chiều rộng và chiều cao của nó), trong khi offsetWidthvà offsetHeightmô tả kích thước của hộp viền giới hạn (sử dụng Element.getBoundingClientRect()để có được vị trí của nó). Do đó, một hộp với trái, hàng đầu, chiều rộng và chiều cao của offsetLeft, offsetTop, offsetWidthvà offsetHeightsẽ không có một hộp bounding cho một khoảng thời với văn bản bọc.
HTMLEuity.offsetTop
Các HTMLElement.offsetTopthuộc tính chỉ đọc trả về khoảng cách của phần tử tương đối hiện tại để phía trên cùng của offsetParentnút.
MouseEvent.pageX
Các pageXthuộc tính chỉ đọc trả về X (ngang) phối hợp theo pixel của sự kiện liên quan đến toàn bộ tài liệu. Thuộc tính này có tính đến bất kỳ cuộn ngang của trang.
MouseEvent.pageY
Các MouseEvent.pageY lợi nhuận chỉ đọc tài sản Y (dọc) phối hợp theo pixel của sự kiện liên quan đến toàn bộ tài liệu. Thuộc tính này có tính đến bất kỳ cuộn dọc của trang.
Để được giải thích thêm, vui lòng xem Mạng của Nhà phát triển 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/HTMLEuity/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLEuity/offsetTop
pagevà offsetsẽ rất hữu ích cho tôi. Cảm ơn bạn đã xem xét yêu cầu này!
Tôi đã thực hiện một giải pháp khác mà tôi nghĩ là rất đơn giản vì vậy tôi nghĩ tôi muốn chia sẻ với các bạn.
Vì vậy, vấn đề đối với tôi là div được kéo sẽ nhảy lên 0,0 cho con trỏ chuột. Vì vậy, tôi cần phải nắm bắt vị trí chuột trên div để điều chỉnh vị trí mới của div.
Tôi đọc các div PageX và PageY và đặt trên cùng và bên trái theo đó và sau đó để lấy các giá trị để điều chỉnh tọa độ để giữ con trỏ ở vị trí ban đầu trong div tôi sử dụng trình nghe onDragStart và lưu trữ e.nativeEvent .layerX và e.nativeEvent.layerY chỉ trong trình kích hoạt ban đầu mới cung cấp cho bạn vị trí chuột trong div có thể kéo được.
Mã ví dụ:
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,
});
}
Tôi hy vọng điều này sẽ giúp được ai đó đã trải qua những vấn đề tương tự mà tôi đã trải qua :)
Bạn phải biết cấu trúc của trang của bạn, bởi vì nếu canvas của bạn là con của một div mà đến lượt nó là con của một div khác ... thì câu chuyện trở nên phức tạp hơn. Đây là mã của tôi cho một canvas nằm trong 2 cấp độ của 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);
});
Câu trả lời ban đầu nói để đặt nó trong iframe. Giải pháp tốt hơn là sử dụng các sự kiện offsetX và offsetY trên khung vẽ có phần đệm được đặt thành 0px.
<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>
Bạn có thể sử dụng getBoudingClientRect()của relativecha mẹ.
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)
})