ค้นหาตำแหน่งเมาส์ที่สัมพันธ์กับองค์ประกอบ


244

ฉันต้องการสร้างแอพการวาดภาพเล็ก ๆ น้อย ๆ โดยใช้ Canvas ดังนั้นฉันต้องหาตำแหน่งของเมาส์บนผืนผ้าใบ


2
วิธีการแก้ปัญหาแบบเต็ม: acko.net/blog/ ......
edA-qa mort-ora-y

3
ฉันชอบความสั้น แต่อธิบายทุกสิ่งที่โพสต์นี้
dwjohnston

นี่เก่ามาก แต่ฉันเพิ่งเริ่มโครงการ GitHub ซึ่งเหนือสิ่งอื่นใดคุณก็ต้องการสิ่งที่คุณต้องการ: brainlessdeveloper.com/mouse-move-interaction-spot-js
Fausto NA

คำตอบ:


177

สำหรับคนที่ใช้ 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แต่ละบรรทัด

ปรับปรุง

มีรุ่นใหม่รุ่น JavaScript เท่านั้นด้านล่างโดย @anytimecoder ดังต่อไปนี้เป็นเบราว์เซอร์ที่สนับสนุน getBoundingClientRect ()


7
มันใช้งานได้กับคุณ @ben ฉันขอขอบคุณ "คำตอบที่ถูกต้อง" หรือแสดงความคิดเห็นในสิ่งที่ยังไม่ได้ผลสำหรับคุณ บางทีฉันสามารถช่วยเพิ่มเติมได้
sparkyspider

8
ควรหลีกเลี่ยงการใช้ $ ('selector') ในตัวจัดการเหตุการณ์ยกเว้นว่าคุณต้องการโค้ดที่ช้ามาก เลือกองค์ประกอบของคุณล่วงหน้าและใช้การอ้างอิงที่เลือกไว้ล่วงหน้าในตัวจัดการของคุณ เช่นเดียวกับ $ (หน้าต่าง) ทำครั้งเดียวและแคช
ออสตินฝรั่งเศส

2
นี่ไม่ใช่การกล่าวถึงที่จำเป็น: หากคุณคัดลอกการวางโค้ดด้านบนอย่าลืมแก้ไขvar y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();ให้ถูกต้องvar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Raj Nathani

77
นั่นอาจเป็นคำตอบได้อย่างไรเนื่องจากคำถามนั้นไม่เกี่ยวข้องกับ jQuery?
FlorianB

2
@Black แต่บางคนถามสิ่งที่เป็น javascript แทนที่จะ jquery เพราะ jquery อาจเข้ากันไม่ได้ในสภาพแวดล้อมของพวกเขา
dbrree

307

เนื่องจากฉันไม่พบคำตอบ 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.
}

JSFiddle จากตัวอย่างเต็ม


2
คุณต้องปัดเศษ rect boundingเพื่อให้แน่ใจว่าค่าจำนวนเต็มด้วยวิธีนี้
Jake Cobb

2
การแก้ไขใหม่ควรแก้ไขปัญหาการเลื่อน (โดยใช้ clientX / Y)
Erik Koopmans

6
คำตอบนี้ควรได้รับการโหวต ขอบคุณ anytimecoder และ @ErikKoopmans
Ivan

3
PSA: ความคิดเห็นของ @mpen ล้าสมัย; วิธีนี้ใช้ได้ผลแม้ในกรณีที่มีการเลื่อน ดู Fiddle รุ่นล่าสุด: jsfiddle.net/6wcsovp2
Xharlie

4
ขอบคุณ! One note: คุณต้องการe.currentTargetไม่ใช่ e.target มิฉะนั้นองค์ประกอบของเด็กจะส่งผลกระทบต่อมัน
Maxim Georgievskiy

60

ข้อมูลต่อไปนี้คำนวณตำแหน่งของเมาส์ที่สัมพันธ์กับองค์ประกอบ Canvas:

var example = document.getElementById('example'); 
example.onmousemove = function(e) { 
    var x = e.pageX - this.offsetLeft; 
    var y = e.pageY - this.offsetTop; 
}

ในตัวอย่างนี้thisหมายถึงexampleองค์ประกอบและeเป็นonmousemoveเหตุการณ์


83
อาจเป็นฉัน แต่เป็นรหัสสองบรรทัดที่ใช้คำหลัก "นี่" ไม่มีบริบทใช่หรือไม่
Deratrius

9
บริบทที่ขาดไปอย่างแน่นอน 'e' เป็นเหตุการณ์และ 'this' เป็นองค์ประกอบที่เหตุการณ์เชื่อมโยงกับ var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
Nick Bisby

22
สิ่งนี้จะไม่ทำงานหากองค์ประกอบที่สืบทอดมาบางอย่างใช้การกำหนดตำแหน่งแบบสัมพันธ์หรือแบบสัมบูรณ์
edA-qa mort-ora-y

12
คุณสามารถสลับthisไปใช้e.currentTargetซึ่งจะทำให้คุณได้ตำแหน่งที่สัมพันธ์กับองค์ประกอบที่คุณเพิ่มผู้ฟังเหตุการณ์
Linus Unnebäck

2
สิ่งนี้ดูเหมือนจะให้ตำแหน่งสัมพันธ์กับส่วนที่มองเห็นได้ขององค์ประกอบไม่ใช่องค์ประกอบทั้งหมด มีวิธีที่จะรองรับสิ่งนั้นหรือไม่หากส่วนหนึ่งขององค์ประกอบไม่สามารถมองเห็นได้ในวิวพอร์ตและมีแถบเลื่อน ฯลฯ ?
frabjous

37

ไม่มีคำตอบในจาวาสคริปต์บริสุทธิ์ที่คืนค่าพิกัดสัมพัทธ์เมื่อองค์ประกอบอ้างอิงซ้อนอยู่ในส่วนอื่นซึ่งสามารถอยู่กับตำแหน่งที่แน่นอน นี่คือวิธีแก้ไขสถานการณ์นี้:

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

}

3
ฉันไม่คิดว่าจะคำนึงถึงhtmlองค์ประกอบของบัญชีเลย
apieceofbart

3
ใช้งานได้ดีกับการเลื่อนภาชนะบรรจุที่มีเพียงการเปลี่ยนแปลงเล็กน้อย: แทนที่ด้วยwhile(reference !== undefined) while(reference)ใน Chrome อย่างน้อย offsetParent ไม่ได้จบลงด้วยการแต่undefined nullเพียงแค่การตรวจสอบว่าreferenceเป็น truthy จะให้แน่ใจว่ามันทำงานร่วมกับทั้งสองและundefined null
blex

ฉันจะให้ +1 อีกถ้าทำได้เพราะให้ฉันรู้ว่ามีoffsetParentทรัพย์สินซึ่งกลายเป็นประโยชน์อย่างมากในสถานการณ์อื่น ๆ !
FonzTech

โดยทั่วไปการตรวจสอบไม่ได้กำหนดมักเป็นความคิดที่ผิด
Juan Mendes

ฉันคิดว่าคุณต้องลบscrollLeftและscrollTopชดเชยลูกหลานที่เลื่อน
Robert

20

สามารถเขียนบทความที่ดีเกี่ยวกับความยากของปัญหานี้ได้ที่: http://www.quirksmode.org/js/events_properties.html#position

ใช้เทคนิคที่อธิบายไว้ที่นั่นคุณสามารถค้นหาตำแหน่ง mouses ในเอกสาร แล้วคุณก็จะตรวจสอบเพื่อดูว่ามันอยู่ภายในขอบเขตกล่องขององค์ประกอบของคุณซึ่งคุณสามารถหาได้โดยการโทรที่จะกลับวัตถุที่มีคุณสมบัติดังต่อไปนี้:element.getBoundingClientRect() { bottom, height, left, right, top, width }จากนั้นมันเป็นเรื่องไม่สำคัญที่จะคิดออกว่าสิ่งที่เกิดขึ้นภายในองค์ประกอบของคุณหรือไม่


1
น่าเศร้าที่สิ่งนี้ล้มเหลวหากมีการหมุนเกิดขึ้น
Eric

17

ฉันลองวิธีแก้ปัญหาทั้งหมดและเนื่องจากการตั้งค่าพิเศษของฉันด้วยเมทริกซ์ที่แปลงคอนเทนเนอร์ (ไลบรารี panzoom) ไม่มีการทำงาน สิ่งนี้จะคืนค่าที่ถูกต้องแม้ว่าจะซูมและเลื่อน:

mouseevent(e) {
 const x = e.offsetX,
       y = e.offsetY
}

แต่เฉพาะในกรณีที่ไม่มีองค์ประกอบของเด็กในทาง สิ่งนี้สามารถหลีกเลี่ยงได้โดยทำให้พวกเขา 'มองไม่เห็น' กับเหตุการณ์โดยใช้ CSS:

.child {
   pointer-events: none;
}

3
นี่คือวิธีการทำสิ่งนี้ในปี 2562 คำตอบอื่น ๆ ทั้งหมดเต็มไปด้วยสัมภาระที่สกปรก
โคลิน D

1
@ColinD ขอบคุณ! ฉันลืมที่จะเพิ่มว่านี้ยังใช้งานได้ใน IE11
Fabian von Ellerts

สิ่งนี้ใช้ได้สำหรับฉัน อย่างไรก็ตามฉันสงสัยว่า 1) ไม่กี่ upvotes 2) คำตอบที่ได้รับคะแนนสูงกว่ามีความซับซ้อนและ 3) ฉันไม่เห็นข้อบกพร่องที่อธิบายไว้ ไม่มีใครรู้ข้อโต้แย้งใด ๆ ของการใช้วิธีการนี
Mark E

1
@ Marke ไม่มีอะไรที่น่าสงสัยเกี่ยวกับมัน เป็นหนึ่งในความผิดพลาดมากมายของ StackOverflow คำตอบที่คุณเห็นที่ด้านบนถูกโพสต์เมื่อหลายปีก่อนคำตอบนี้ที่นี่ดังนั้นพวกเขาจึงได้รับแรงผลักดันจากการโหวตอย่างมากมาย เมื่อคำตอบได้รับโมเมนตัมนี้มันยากและยากที่จะเอาชนะ
Jack Giffin

9

ฉันเจอคำถามนี้ แต่เพื่อให้มันทำงานได้กับกรณีของฉัน (โดยใช้ dragover บนองค์ประกอบ DOM (ไม่ใช่ผ้าใบในกรณีของฉัน)) ฉันพบว่าคุณต้องใช้offsetXและoffsetYในเหตุการณ์ dragover-mouse เท่านั้น .

onDragOver(event){
 var x = event.offsetX;
 var y = event.offsetY;
}

2
มันใช้งานได้ดีสำหรับฉัน ทำไมไม่มีใครโหวตสิ่งนี้ ฉันสงสัยว่ามีข้อผิดพลาดหรือไม่ หากฉันพบสิ่งใดฉันจะรายงานกลับ!
ปลากะพงขาว

7
event.offsetX สัมพันธ์กับองค์ประกอบที่ตัวชี้เมาส์อยู่เหนือไม่ใช่องค์ประกอบที่มีฟัง dragover ที่แนบมา หากคุณไม่มีโครงสร้างองค์ประกอบซ้อนกันนี่เป็นเรื่องปกติ แต่ถ้าคุณทำสิ่งนี้จะไม่ทำงาน
opsb

7

ฉัน +1 'คำตอบของมาร์ค van Wyk เพราะมันทำให้ฉันไปในทิศทางที่ถูกต้อง แต่ก็ไม่ได้แก้ปัญหาสำหรับฉัน ฉันยังคงมีการชดเชยในการวาดภาพในองค์ประกอบที่มีอยู่ในองค์ประกอบอื่น

การไหลแก้มันสำหรับฉัน:

        x = e.pageX - this.offsetLeft - $(elem).offset().left;
        y = e.pageY - this.offsetTop - $(elem).offset().top;

ในคำอื่น ๆ - ฉันเพียงแค่ซ้อน offsets ทั้งหมดจากองค์ประกอบทั้งหมดซ้อนกัน


+1 สำหรับคุณ! นี่คือคำตอบที่ฉันต้องการ ฉันมีสองผืนผ้าใบซ้อนกันอยู่ด้านบนและพิกัดทั้งหมดผิดเพราะกองอื่น ๆ ฉันรู้ว่านี่เป็นปัญหา แต่ไม่ทราบตรรกะ / สมการเพื่อชดเชย คุณก็แก้ไขปัญหาของฉันด้วย! = D ขอบคุณ!
Partack

5

คำตอบข้างต้นไม่เป็นที่น่าพอใจ 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

4

สำหรับผู้ที่คุณพัฒนาเว็บไซต์ปกติหรือ PWAs (Progressive Web Apps) สำหรับอุปกรณ์มือถือและ / หรือแล็ปท็อป / จอภาพที่มีหน้าจอสัมผัสคุณจะต้องลงจอดที่นี่เพราะคุณอาจเคยชินกับเหตุการณ์เมาส์และเป็นประสบการณ์ใหม่ของ Touch กิจกรรม ... ใช่!

มี 3 กฎเท่านั้น:

  1. ทำน้อยที่สุดในระหว่างmousemoveหรือtouchmoveกิจกรรม
  2. ทำมากที่สุดในช่วงmousedownหรือtouchstartกิจกรรม
  3. ยกเลิกการแพร่กระจายและป้องกันการตั้งค่าเริ่มต้นสำหรับเหตุการณ์การสัมผัสเพื่อป้องกันเหตุการณ์เมาส์จากการยิงบนอุปกรณ์ไฮบริด

จำเป็นต้องพูดสิ่งต่าง ๆ มีความซับซ้อนมากขึ้นกับ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">

3

คุณสามารถรับมันได้โดย

var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
    var xCoor = e.clientX;
    var yCoor = e.clientY;
}

จะใช้งานได้ใน IE หรือ IE ยังคงใช้ window.event แทนที่จะส่งเหตุการณ์ไปยังอาร์กิวเมนต์แรกของผู้ฟังหรือไม่ แก้ไข - ฉันเดา IE ขาดองค์ประกอบผ้าใบต่อไปจนถึงรุ่นที่ 9 แต่ตอนนี้จะยังคงอาจ IE สนับสนุนเพราะสิ่งที่ต้องการ excanvas ....
Dagg Nabbit

21
สิ่งนี้จะให้พิกัดที่สัมพันธ์กับหน้าต่างเบราว์เซอร์ยังคงต้องคิดว่าพวกเขาอยู่ในองค์ประกอบโดยใช้ element.getBoundingClientRect ()
David W. Keith

ขอบคุณที่ทำให้ฉันรับรู้ถึง getBoundingClientRect !!!! ฉันไม่เคยรู้เลยว่ามีเรื่องแบบนี้!
Gershom

@ DavidW.Keith ความคิดเห็นควรได้รับการพิจารณาคำตอบที่ถูกต้องจริงๆ!
Ulrik S

3

นำมาจากบทช่วยสอนนี้พร้อมการแก้ไขที่ทำขึ้นจากความคิดเห็นยอดนิยม:

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

3

ฉันรู้ว่าฉันมาสายนิดหน่อย แต่มันใช้งานได้กับจาวาสคริปต์ 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.


1
ขอบคุณที่เป็นผู้ตอบเพียงคนเดียวที่คิดเกี่ยวกับการเลื่อน ลองเปลี่ยนคำตอบเพื่อเพิ่มแกน y เช่นกัน
frabjous

3

ตามโซลูชันของ @ 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;
}

สิ่งนี้ใช้ได้ทั้งกับการเลื่อนและการซูม (ซึ่งในบางครั้งมันจะคืนค่าลอย)


ฉันต้องการอัปโหลด แต่ไม่ควรลบเครื่องหมายสำหรับหน้า offsets หรือไม่ เป็นอย่างนั้นหรือวงเล็บในส่วนที่สองหรือไม่?
Chris Sunami สนับสนุน Monica

1

สามารถรับค่าพิกัดของเมาส์ภายในพื้นที่วาดภาพได้ด้วย 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>
    


มันใช้งานไม่ได้หากกองกำลังอีกกองซ้อนทับผืนผ้าใบเหมือนที่ @opsb พูด
David Peicho

1
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และอธิบายกล่องชายแดนขององค์ประกอบที่สัมพันธ์กับoffsetHeightoffsetParent

อย่างไรก็ตามสำหรับองค์ประกอบระดับอินไลน์ (เช่น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 Developer Network:

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


ในขณะที่ข้อมูลโค้ดนี้อาจแก้ปัญหาได้รวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ
Patrick Hund

ฉันหวังว่าผู้อ่านในอนาคตจะมี JS API ซึ่งจะคำนวณสิ่งนี้สำหรับพวกเขา ;-) นี่อาจเป็นคำตอบที่ง่ายที่สุดเต็มอยู่ในตัวเอง การแสดงความคิดเห็นรหัสอธิบายตนเองเป็นเพียงเรื่องเสียสมาธิ
lama12345

ฉันขอ @ PatrickHund สองเพื่อขอคำอธิบาย ฉันไม่ใช่ผู้เชี่ยวชาญ CSS / JS และรู้เพิ่มเติมเกี่ยวกับความสัมพันธ์ระหว่างเช่นpageและoffsetจะเป็นประโยชน์กับฉันมาก ขอบคุณสำหรับการพิจารณาคำขอนี้!
cxw

@cxw ตกลงคุณเป็น downvote ที่ 2 ตอนนี้ (มี 1 upvote) ... ฉันได้เพิ่มคำอธิบายที่ยาวลงไปในตอนนี้มันก็เหมือนกับ 10x ตราบเท่าที่โค้ด 4 บรรทัด ยินดีต้อนรับคุณได้อ่านสนุก ฉันพิจารณาคำขอของคุณแล้ว! : p
lama12345

1
@cxw ฉันยุ่งโดยการเพิ่มองค์ประกอบตำแหน่งที่แน่นอนพิเศษและบังคับให้องค์ประกอบผ้าใบตัวเองนอกจอเช่นกันดังนั้นฉันจึงต้องเลื่อนไปที่มันเช่นซ้าย / บน 2000px offscreen ไม่สามารถรับรหัสนี้ได้
lama12345

1

ฉันใช้โซลูชันอื่นที่ฉันคิดว่าง่ายมากดังนั้นฉันคิดว่าฉันจะแบ่งปันกับพวกคุณ

ดังนั้นปัญหาสำหรับฉันก็คือ div div ที่ลากนั้นจะกระโดดไปที่0,0สำหรับเคอร์เซอร์ของเมาส์ ดังนั้นฉันจึงต้องจับตำแหน่ง mouses บน div เพื่อปรับตำแหน่ง divs ใหม่

ฉันอ่าน div ของ PageX และ PageY แล้วตั้งค่าด้านบนและด้านซ้ายตามนั้นและเพื่อให้ได้ค่าสำหรับปรับพิกัดเพื่อให้เคอร์เซอร์อยู่ในตำแหน่งเริ่มต้นใน div ฉันใช้ฟัง onDragStart และเก็บe.nativeEvent .layerXและe.nativeEvent.layerYที่เฉพาะในทริกเกอร์เริ่มต้นเท่านั้นที่จะช่วยให้คุณได้รับตำแหน่ง mouses ภายใน div ที่ลากได้

รหัสตัวอย่าง:

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

ฉันหวังว่านี้จะช่วยให้คนที่ประสบปัญหาเดียวกันกับที่ฉันผ่าน :)


1
function myFunction(e) {
    var x =  e.clientX - e.currentTarget.offsetLeft ; 
    var y = e.clientY - e.currentTarget.offsetTop ;
}

ใช้งานได้ดี!


0

คุณต้องรู้โครงสร้างของหน้าเว็บของคุณเพราะถ้าผืนผ้าใบของคุณเป็นลูกของ 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);

});


0

คำตอบเดิมบอกว่าจะใส่ไว้ใน iframe ทางออกที่ดีกว่าคือการใช้ events offsetX และ offsetY บนผืนผ้าใบที่มีการเว้นระยะห่างไว้ที่ 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>

0

นี่คือสิ่งที่ฉันได้รับ

    $(".some-class").click(function(e) {

    var posx = 0;
    var posy = 0;

    posx = e.pageX;
    posy = e.pageY;

    alert(posx);
    alert(posy);
});

0

คุณสามารถใช้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)
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.