jQuery mendapatkan posisi mouse dalam suatu elemen

165

Saya berharap untuk membuat kontrol di mana pengguna dapat mengklik di dalam div, lalu seret mouse, lalu biarkan mouse untuk menunjukkan berapa lama mereka menginginkan sesuatu. (Ini untuk kontrol kalender, sehingga pengguna akan menunjukkan panjang, waktu, dari peristiwa tertentu)

Sepertinya cara terbaik untuk melakukan ini adalah dengan mendaftarkan acara "mousedown" pada div induk yang pada gilirannya mendaftarkan acara "mousemove" pada div hingga acara "mouseup" dipicu. Acara "mousedown" dan "mouseup" akan menentukan awal dan akhir rentang waktu dan saat saya mengikuti acara "mousemove", saya dapat secara dinamis mengubah ukuran rentang sehingga pengguna dapat melihat apa yang mereka lakukan. Saya mendasarkan ini pada bagaimana acara dibuat di kalender google.

Masalah yang saya alami adalah bahwa acara jQuery tampaknya hanya memberikan informasi koordinat mouse yang dapat diandalkan sehubungan dengan seluruh halaman. Apakah ada cara untuk mengetahui koordinat apa yang mengacu pada elemen induk?

Edit:

Inilah gambar dari apa yang saya coba lakukan: teks alternatif

Chris Dutrow
sumber

Jawaban:

305

Salah satu caranya adalah dengan menggunakan offsetmetode jQuery untuk menerjemahkan event.pageXdan event.pageYmengoordinasikan dari acara ke posisi mouse relatif terhadap induknya. Berikut ini contoh untuk referensi di masa mendatang:

$("#something").click(function(e){
   var parentOffset = $(this).parent().offset(); 
   //or $(this).offset(); if you really just want the current element's offset
   var relX = e.pageX - parentOffset.left;
   var relY = e.pageY - parentOffset.top;
});
jball
sumber
2
Ya ini adalah ide bagus jika tata letak elemen induk tidak dapat / tidak boleh diubah!
Runcing
2
Apakah jawaban ini memperhitungkan padding / batas akun?
LeeGee
10
Menurut dokumen, offset tidak memperhitungkan "untuk batas, margin, atau bantalan yang ditetapkan pada elemen tubuh." Saya belum menemukan masalah dengan jawaban yang saya kirim yang digunakan, tetapi mungkin lebih baik untuk memeriksa mereka yang ditetapkan.
jball
2
Ini tidak harus berhasil. offset()juga relatif, jadi jika orang tua adalah anak dari elemen lain, ini akan memberikan hasil yang salah. Gunakan position()sebagai gantinya.
Flash Guntur
1
@FlashThunder offset () tidak relatif, setidaknya tidak menurut dokumen. Juga harus menjadi praktik standar untuk tidak memiliki margin atau bantalan pada elemen tubuh.
James Watkins
18

Untuk mendapatkan posisi klik relatif terhadap elemen yang diklik saat
ini Gunakan kode ini

$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 
Sajjad Ashraf
sumber
2
Jawaban Anda membantu saya BTW, jawaban yang diterima tidak. Terima kasih :) Apa yang sebenarnya saya gunakan adalah ini, sebagai gantinya: var y = e.pageY - $(this).offset().top;Tapi jawaban Anda membawa saya ke jalan yang benar.
Solomon Closson
11

Saya menggunakan kode ini, cukup bagus :)

    <script language="javascript" src="http://code.jquery.com/jquery-1.4.1.js" type="text/javascript"></script>
<script language="javascript">
$(document).ready(function(){
    $(".div_container").mousemove(function(e){
        var parentOffset = $(this).parent().offset();
        var relativeXPosition = (e.pageX - parentOffset.left); //offset -> method allows you to retrieve the current position of an element 'relative' to the document
        var relativeYPosition = (e.pageY - parentOffset.top);
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    }).mouseout(function(){
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    });
});
</script>
Maarten Hartman
sumber
9

@AbdulRahim jawabannya hampir benar. Tapi saya sarankan fungsi di bawah ini sebagai pengganti (untuk referensi lebih lanjut):

function getXY(evt, element) {
                var rect = element.getBoundingClientRect();
                var scrollTop = document.documentElement.scrollTop?
                                document.documentElement.scrollTop:document.body.scrollTop;
                var scrollLeft = document.documentElement.scrollLeft?                   
                                document.documentElement.scrollLeft:document.body.scrollLeft;
                var elementLeft = rect.left+scrollLeft;  
                var elementTop = rect.top+scrollTop;

                x = evt.pageX-elementLeft;
                y = evt.pageY-elementTop;

                return {x:x, y:y};
            }




            $('#main-canvas').mousemove(function(e){
                var m=getXY(e, this);
                console.log(m.x, m.y);
            });
Paulo Bueno
sumber
1
Peningkatan luar biasa, menyelamatkan hari saya.
Bud Damyanov
hampir, tambahkan margin ke kanvas dan Anda tidak aktif dengan margin
Benn
Ini adalah kode yang sangat bagus, terima kasih banyak!
Stefan
7

Solusi ini mendukung semua browser utama termasuk IE. Ini juga menangani pengguliran. Pertama, ia mengambil posisi elemen relatif ke halaman secara efisien, dan tanpa menggunakan fungsi rekursif. Kemudian ia mendapat x dan y dari klik mouse relatif ke halaman dan melakukan pengurangan untuk mendapatkan jawaban yang merupakan posisi relatif terhadap elemen (elemen dapat berupa gambar atau div misalnya):

function getXY(evt) {
    var element = document.getElementById('elementId');  //replace elementId with your element's Id.
    var rect = element.getBoundingClientRect();
    var scrollTop = document.documentElement.scrollTop?
                    document.documentElement.scrollTop:document.body.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft?                   
                    document.documentElement.scrollLeft:document.body.scrollLeft;
    var elementLeft = rect.left+scrollLeft;  
    var elementTop = rect.top+scrollTop;

        if (document.all){ //detects using IE   
            x = event.clientX+scrollLeft-elementLeft; //event not evt because of IE
            y = event.clientY+scrollTop-elementTop;
        }
        else{
            x = evt.pageX-elementLeft;
            y = evt.pageY-elementTop;
    }
Abdul Rahim Haddad
sumber
3

Jika Anda membuat elemen induk Anda menjadi "position: relative", maka itu akan menjadi "parent offset" untuk hal-hal yang Anda lacak aktivitas tetikusnya. Dengan demikian "posisi ()" jQuery akan relatif terhadap itu.

Runcing
sumber
Hei Pointy, terima kasih atas tanggapan Anda. Berdasarkan kata-kata Anda, sepertinya apa yang Anda sarankan berbeda dari apa yang disarankan jball, tapi saya tidak mengerti bagaimana, bisakah Anda menguraikannya? Terima kasih lagi
Chris Dutrow
@ DebrowLLC, Pointy menyarankan untuk mengubah gaya elemen induk untuk dimiliki "position:relative". Posisi jQuery kemudian akan melaporkan posisinya relatif ke elemen induk, bukan halaman. Kata-kata pada jawaban saya buruk, itu menyiratkan bahwa itu terkait langsung dengan solusi Pointy, tetapi itu adalah cara menghitung offset ketika Anda tidak bisa atau tidak ingin bergantung pada atribut gaya elemen induk.
jball
Jadi jika saya mengatur "position: relative" jQuery akan melaporkan posisi relatiove dengan benar di semua browser? Alasan saya bertanya adalah karena dokumentasi jQuery tampaknya menyiratkan bahwa satu-satunya posisi mouse yang dapat diandalkan di semua browser adalah yang terkait dengan jendela browser itu sendiri.
Chris Dutrow
Sebuah kotak dengan "posisi: relatif" akan membuat pengaturan "atas" dan "kiri" (dll) untuk kotak anak oleh relatif terhadap persegi panjang konten kotak induk relatif.
Runcing
Saya mungkin melakukan sesuatu yang salah, tetapi ini sepertinya tidak berhasil di firefox. Saya memiliki "posisi: relatif;" ditetapkan pada induknya, firefox melaporkan event.pageX dan event.clientX secara identik (sehubungan dengan bagian atas, kiri halaman) dan melaporkan event.offsetX sebagai tidak terdefinisi
Chris Dutrow
2

Ini adalah salah satu yang juga memberi Anda posisi persen jika Anda membutuhkannya. https://jsfiddle.net/Themezly/2etbhw01/

function ThzhotspotPosition(evt, el, hotspotsize, percent) {
  var left = el.offset().left;
  var top = el.offset().top;
  var hotspot = hotspotsize ? hotspotsize : 0;
  if (percent) {
    x = (evt.pageX - left - (hotspot / 2)) / el.outerWidth() * 100 + '%';
    y = (evt.pageY - top - (hotspot / 2)) / el.outerHeight() * 100 + '%';
  } else {
    x = (evt.pageX - left - (hotspot / 2));
    y = (evt.pageY - top - (hotspot / 2));
  }

  return {
    x: x,
    y: y
  };
}



$(function() {

  $('.box').click(function(e) {

    var hp = ThzhotspotPosition(e, $(this), 20, true); // true = percent | false or no attr = px

    var hotspot = $('<div class="hotspot">').css({
      left: hp.x,
      top: hp.y,
    });
    $(this).append(hotspot);
    $("span").text("X: " + hp.x + ", Y: " + hp.y);
  });


});
.box {
  width: 400px;
  height: 400px;
  background: #efefef;
  margin: 20px;
  padding: 20px;
  position: relative;
  top: 20px;
  left: 20px;
}

.hotspot {
  position: absolute;
  left: 0;
  top: 0;
  height: 20px;
  width: 20px;
  background: green;
  border-radius: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
  <p>Hotspot position is at: <span></span></p>
</div>

Benn
sumber
-1

Saya akan menyarankan ini:

e.pageX - this.getBoundingClientRect().left
Eduard
sumber