Bagaimana cara mendapatkan koordinat klik mouse pada elemen kanvas?

276

Apa cara paling sederhana untuk menambahkan event handler klik ke elemen kanvas yang akan mengembalikan koordinat x dan y klik (relatif terhadap elemen kanvas)?

Tidak diperlukan kompatibilitas browser lama, Safari, Opera, dan Firefox akan melakukannya.

Tom
sumber
Ini seharusnya tidak berbeda dengan mendapatkan acara mouse dari elemen dom normal. quirksmode memiliki referensi yang bagus tentang itu.
airportyh
4
Kode yang Anda sebutkan di atas hanya berfungsi ketika kanvas tidak jauh di dalam wadah lain. Secara umum Anda perlu menggunakan sesuatu seperti fungsi offset jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] untuk mendapatkan offset yang benar dengan cara lintas browser. Ini benar-benar menyebalkan.
Aaron Watters
Kode yang diposting di atas dengan Pembaruan gagal berfungsi jika halaman yang berisi gulungan kanvas.
Timothy Kim
Saya menghapus "jawaban" lama saya yang disertakan sebagai pembaruan untuk pertanyaan. Seperti yang disebutkan, itu ketinggalan zaman dan tidak lengkap.
Tom
3
Karena ada 50 jawaban di sini, saya sarankan untuk melihat jawaban orang-orang ini: patriques - 5 liner yang bagus dan sederhana.
Igor L.

Jawaban:

77

Sunting 2018: Jawaban ini cukup lama dan menggunakan pemeriksaan untuk browser lama yang tidak diperlukan lagi, karena clientXdan clientYproperti bekerja di semua browser saat ini. Anda mungkin ingin memeriksa Patriques Answer untuk solusi yang lebih sederhana dan lebih baru.

Jawaban Asli:
Seperti yang dijelaskan dalam artikel yang saya temukan saat itu tetapi tidak ada lagi:

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;

Bekerja dengan sangat baik untuk saya.

N4ppeL
sumber
30
Solusi ini tidak selalu berhasil - jawaban Ryan Artecona bekerja dalam kasus yang lebih umum ketika kanvas tidak selalu diposisikan relatif terhadap seluruh halaman.
Chris Johnson
3
Solusi ini tidak cocok jika masalah kinerja, karena akses Dom dilakukan pada setiap klik / pindah. Dan getBoundingClientRect ada sekarang, dan lebih elegan.
GameAlchemist
192

Jika Anda suka kesederhanaan tetapi tetap menginginkan fungsionalitas lintas-browser, saya menemukan solusi ini paling cocok untuk saya. Ini adalah penyederhanaan dari solusi @ Aldekein tetapi tanpa 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)
})
patriques
sumber
Jika halaman digulir ke bawah, saya kira orang juga harus mempertimbangkan offset gulir dokumen.
Peppe LG
8
@ Persegi panjang klien terikat PeppeL-G menghitung itu untuk Anda. Anda dapat dengan mudah mengujinya di konsol sebelum mengirim komentar (itulah yang saya lakukan).
Tomáš Zato - Reinstate Monica
1
@ TomášZato, oh, getBoundingClientRectmengembalikan posisi relatif ke port tampilan? Kemudian tebakan saya salah. Saya tidak pernah mengujinya karena ini tidak pernah menjadi masalah bagi saya, dan saya ingin memperingatkan pembaca lain tentang potensi masalah yang saya lihat, tetapi terima kasih atas klarifikasi Anda.
Peppe LG
1
Ini tidak berfungsi jika kanvas diskalakan. Tidak yakin apakah itu bug browser.
Jeroen
2
Tambahkan penggunaan untuk seseorang seperti saya:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion
179

Memperbarui (5/5/16): Jawaban patriques harus digunakan sebagai gantinya, karena lebih sederhana dan lebih dapat diandalkan.


Karena kanvas tidak selalu ditata relatif terhadap seluruh halaman, kanvas canvas.offsetLeft/Toptidak selalu mengembalikan apa yang Anda butuhkan. Ini akan mengembalikan jumlah piksel yang diimbangi relatif terhadap elemen offsetParentnya, yang bisa berupa divelemen yang mengandung kanvas denganposition: relative gaya yang diterapkan. Untuk menjelaskan ini, Anda perlu mengulang melalui rantai offsetParents, dimulai dengan elemen kanvas itu sendiri. Kode ini berfungsi dengan baik untuk saya, diuji di Firefox dan Safari tetapi harus bekerja untuk semua.

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;

Baris terakhir memudahkan untuk mendapatkan koordinat mouse relatif terhadap elemen kanvas. Yang diperlukan untuk mendapatkan koordinat yang bermanfaat adalah

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Ryan Artecona
sumber
8
Tidak, ini menggunakan objek prototipe javascript bawaan --- developer.mozilla.org/en/…
garg
14
Chrome saya memiliki event.offsetXdan event.offsetYatribut, jadi saya memodifikasi solusi Anda dengan menambahkan if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. Sepertinya itu berfungsi.
Baczek
3
Baczek benar tentang Chrome event.offsetXdan event.offsetYyang juga berfungsi di IE9. Untuk Firefox (diuji dengan v13), Anda dapat menggunakan event.layerXdan event.layerY.
mafafu
3
Saya juga menambahkan ini: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc
4
Versi terakhir pada jawaban ini tidak berfungsi untuk saya. Di Firefox, jika seluruh layar digulir, saya mendapat nilai yang dipindahkan sebagai output. Apa yang berhasil bagi saya adalah solusi yang sangat mirip, diberikan pada stackoverflow.com/a/10816667/578749 yang alih-alih event.pageX / Y, itu dikurangi offset yang dihitung dari event.clientX / Y. Bisakah seseorang mengulas ini dan menjelaskan?
lvella
33

Peramban modern sekarang menangani ini untuk Anda. Chrome, IE9, dan Firefox mendukung offsetX / Y seperti ini, melewati acara dari pengendali klik.

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

Sebagian besar browser modern juga mendukung layerX / Y, namun Chrome dan IE menggunakan layerX / Y untuk offset absolut dari klik pada halaman termasuk margin, padding, dll. Di Firefox, layerX / Y dan offsetX / Y adalah setara, tetapi offset tidak sebelumnya sudah ada. Jadi, untuk kompatibilitas dengan browser yang sedikit lebih tua, Anda dapat menggunakan:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
mafafu
sumber
1
menarik bagaimana layerX, layerY didefinisikan pada Chrome dan Firefox, tetapi pada Chrome itu tidak akurat (atau berarti sesuatu yang lain).
Julian Mann
@JulianMann Terima kasih atas informasinya. Saya telah memperbarui jawaban ini berdasarkan lebih banyak dukungan saat ini. Sepertinya Anda dapat pergi dengan offsetX / Y hampir secara universal sekarang.
mafafu
18

Menurut segar Quirksmode yang clientXdan clientYmetode yang didukung di semua browser utama. Jadi, begini - kode yang bagus dan berfungsi yang bekerja dalam scrolling div pada halaman dengan scrollbar:

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

Ini juga memerlukan jQuery untuk $(canvas).offset().

Aldekein
sumber
Setara dengan jawaban @ N4ppeL.
Paweł Szczur
13

Saya membuat demostrasi penuh yang berfungsi di setiap browser dengan kode sumber lengkap dari solusi masalah ini: Koordinat klik mouse pada Canvas dalam Javascript . Untuk mencoba demo, salin kode dan tempel ke editor teks. Kemudian simpan sebagai example.html dan, akhirnya, buka file dengan browser.

Manuel Ignacio López Quintero
sumber
11

Berikut ini adalah modifikasi kecil untuk jawaban Ryan Artecona untuk kanvas dengan lebar variabel (%):

 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}
}
Cryptovirus
sumber
7

Berhati-hatilah saat melakukan konversi koordinat; ada beberapa nilai non-lintas-browser yang dikembalikan dalam acara klik. Menggunakan clientX dan clientY saja tidak cukup jika jendela browser digulir (diverifikasi di Firefox 3.5 dan Chrome 3.0).

Artikel mode quirks ini menyediakan fungsi yang lebih benar yang dapat menggunakan pageX atau pageY atau kombinasi clientX dengan document.body.scrollLeft dan clientY dengan document.body.scrollTop untuk menghitung koordinat klik relatif terhadap asal dokumen.

UPDATE: Selain itu, offsetLeft dan offsetTop relatif terhadap ukuran elemen yang empuk, bukan ukuran interior. Kanvas dengan padding: style yang diterapkan tidak akan melaporkan kiri atas wilayah kontennya sebagai offsetLeft. Ada berbagai solusi untuk masalah ini; yang paling sederhana mungkin untuk menghapus semua gaya border, padding, dll. pada kanvas itu sendiri dan sebaliknya menerapkannya ke kotak yang berisi kanvas.

fixermark
sumber
7

Saya tidak yakin apa gunanya semua jawaban ini yang berulang melalui elemen induk dan melakukan semua jenis hal aneh .

The HTMLElement.getBoundingClientRectMetode ini dirancang untuk menangani posisi layar yang sebenarnya dari setiap elemen. Ini termasuk menggulir, jadi hal-hal seperti scrollToptidak diperlukan:

(dari MDN) Jumlah pengguliran yang telah dilakukan dari area viewport (atau elemen yang dapat digulir lainnya ) diperhitungkan saat menghitung persegi panjang pembatas

Gambar normal

The pendekatan yang sangat sederhana sudah diposting di sini. Ini benar selama tidak ada aturan CSS liar yang terlibat.

Menangani kanvas / gambar yang diregangkan

Saat lebar piksel gambar tidak cocok dengan lebar CSSnya, Anda harus menerapkan beberapa rasio pada nilai piksel:

/* 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];
}

Selama kanvas tidak memiliki batas, ia berfungsi untuk gambar yang diregangkan (jsFiddle) .

Menangani batas CSS

Jika kanvas memiliki batas tebal, hal-hal menjadi sedikit rumit . Anda benar-benar harus mengurangi batas dari persegi panjang pembatas. Ini dapat dilakukan dengan menggunakan .getComputedStyle . Jawaban ini menjelaskan prosesnya .

Fungsi kemudian tumbuh sedikit:

/* 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
  ...
}

Saya tidak bisa memikirkan apa pun yang akan membingungkan fungsi akhir ini. Lihat dirimu di JsFiddle .

Catatan

Jika Anda tidak suka memodifikasi asli prototype, cukup ubah fungsinya dan panggil dengan (canvas, event)(dan ganti thisdengan canvas).

Tomáš Zato - Pasang kembali Monica
sumber
6

Ini adalah tutorial yang sangat bagus

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

semoga ini membantu!

FraZer
sumber
Solusi Ryan Artecona tidak berfungsi untuk browser tablet dengan zoom. Namun yang ini berhasil.
Andy Meyers
Tidak berfungsi dengan gambar yang memiliki CSS width/ heightoverride tetapi masih merupakan salah satu solusi terbaik.
Tomáš Zato - Pasang kembali Monica
3

Menggunakan jQuery pada tahun 2016, untuk mendapatkan koordinat klik relatif terhadap kanvas, saya lakukan:

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

Ini berfungsi karena kanvas offset () dan jqEvent.pageX / Y relatif terhadap dokumen apa pun posisi gulirnya.

Perhatikan bahwa jika kanvas Anda diskalakan maka koordinat ini tidak sama dengan koordinat logis kanvas . Untuk mendapatkannya, Anda juga harus:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}
Sarsaparilla
sumber
Wow. Bagaimana 'jqEvent' didefinisikan? Atau 'kanvas'? Atau dalam contoh kedua 'coords'? Apakah Anda perlu menjalankan contoh pertama sebelum yang kedua? Dalam hal itu, mengapa Anda tidak menulis "untuk mendapatkan itu, Anda JUGA akan melakukannya"? Apakah ini semua masuk dalam fungsi onclick atau apa? Berikan sedikit konteks, sobat. Dan mengingat pertanyaan awal ditanyakan pada tahun 2008, saya pikir Anda perlu menjawab dalam konteks teknologi yang tersedia pada tahun 2008. Perbaiki jawaban Anda menggunakan jQuery yang valid dari versi yang tersedia saat itu (v1.2). ;)
Ayelis
1
OK, maaf atas kelonggaran saya. Saya akan mengedit untuk menghapus itu. Saya memang berniat untuk memberikan jawaban menggunakan kerangka kerja terbaru. Dan saya percaya seorang programmer tidak perlu dijelaskan apa itu jqEvent, kanvas, dan coord.
Sarsaparilla
Kelihatan bagus. Terima kasih atas masukan Anda! Maaf saya memberi Anda waktu yang sulit! ;)
Ayelis
3

Jadi ini adalah topik yang sederhana namun sedikit lebih rumit dari yang terlihat.

Pertama, biasanya ada pertanyaan yang disatukan di sini

  1. Cara mendapatkan koordinat relatif elemen mouse

  2. Cara mendapatkan koordinat kanvas pixel mouse untuk 2D Canvas API atau WebGL

jadi, jawablah

Cara mendapatkan koordinat relatif elemen mouse

Apakah elemen adalah kanvas yang mendapatkan elemen koordinat mouse relatif sama untuk semua elemen.

Ada 2 jawaban sederhana untuk pertanyaan "Cara mendapatkan koordinat kanvas relatif mouse"

Jawaban sederhana penggunaan # 1 offsetXdanoffsetY

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

Jawaban ini berfungsi di Chrome, Firefox, dan Safari. Tidak seperti semua nilai acara lainnya offsetXdan offsetYmemperhitungkan transformasi CSS.

Masalah terbesar dengan offsetXdan offsetYpada 2019/05 mereka tidak ada pada acara sentuh sehingga tidak dapat digunakan dengan iOS Safari. Mereka memang ada di Acara Pointer yang ada di Chrome dan Firefox tetapi tidak Safari meskipun Safari tampaknya bekerja di sana .

Masalah lainnya adalah acara harus di kanvas itu sendiri. Jika Anda meletakkannya di beberapa elemen lain atau jendela, Anda tidak dapat kemudian memilih kanvas untuk menjadi referensi Anda.

Jawaban sederhana # 2 gunakan clientX, clientYdancanvas.getBoundingClientRect

Jika Anda tidak peduli dengan transformasi CSS, jawaban paling sederhana berikutnya adalah memanggil canvas. getBoundingClientRect()dan mengurangi yang tersisa dari clientXdan topdari clientYseperti pada

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

Ini akan berfungsi selama tidak ada transformasi CSS. Ini juga berfungsi dengan acara sentuh dan begitu juga bekerja dengan 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;
});

Cara mendapatkan koordinat kanvas pixel mouse untuk 2D Canvas API

Untuk ini kita perlu mengambil nilai yang kita dapatkan di atas dan mengkonversi dari ukuran kanvas yang ditampilkan ke jumlah piksel di kanvas itu sendiri

dengan canvas.getBoundingClientRectdan clientXdanclientY

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

atau dengan offsetXdanoffsetY

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

Catatan: Dalam semua kasus, jangan menambahkan bantalan atau batas pada kanvas. Melakukan hal itu akan sangat menyulitkan kode. Alih-alih Anda ingin perbatasan atau bantalan mengelilingi kanvas di beberapa elemen lain dan menambahkan bantalan dan atau perbatasan ke elemen luar.

Contoh kerja menggunakan event.offsetX,event.offsetY

Contoh kerja menggunakan canvas.getBoundingClientRectdan event.clientXdanevent.clientY

gman
sumber
2

Saya merekomendasikan tautan ini - 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>

sumber
apa gunanya x = new Number()? Kode di bawah ini yang menetapkan ulang xyang berarti Nomor yang dialokasikan segera dibuang
gman
1

Anda bisa melakukannya:

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

Ini akan memberi Anda posisi tepat dari penunjuk mouse.

pengguna2310569
sumber
1

Lihat demo di 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 };
  }
Daniel Patru
sumber
0

Berikut adalah beberapa modifikasi dari solusi Ryan Artecona di atas.

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};
}
Simon Hai
sumber
0

Pertama, seperti yang dikatakan orang lain, Anda perlu fungsi untuk mendapatkan posisi elemen kanvas . Berikut adalah metode yang sedikit lebih elegan daripada beberapa yang lain di halaman ini (IMHO). Anda bisa memberikannya elemen apa saja dan mendapatkan posisinya di dokumen:

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

Sekarang hitung posisi kursor saat ini relatif terhadap itu:

$('#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);
});

Perhatikan bahwa saya telah memisahkan findPosfungsi generik dari kode penanganan peristiwa. ( Seperti seharusnya . Kita masing-masing harus mencoba menjaga fungsi kita untuk satu tugas.)

Nilai-nilai offsetLeftdan offsetToprelatif terhadap offsetParent, yang bisa berupa beberapa divsimpul pembungkus (atau apa pun, dalam hal ini). Ketika tidak ada elemen yang membungkus canvasmereka relatif terhadap body, jadi tidak ada offset untuk mengurangi. Inilah sebabnya mengapa kita perlu menentukan posisi kanvas sebelum kita dapat melakukan hal lain.

Mirip, e.pageXdan e.pageYberikan posisi kursor relatif terhadap dokumen. Itu sebabnya kami mengurangi offset kanvas dari nilai-nilai itu untuk sampai pada posisi sebenarnya.

Alternatif untuk elemen yang diposisikan adalah secara langsung menggunakan nilai-nilai e.layerXdan e.layerY. Ini kurang dapat diandalkan daripada metode di atas karena dua alasan:

  1. Nilai-nilai ini juga relatif terhadap seluruh dokumen ketika acara tidak terjadi di dalam elemen yang diposisikan
  2. Mereka bukan bagian dari standar apa pun
Wayne
sumber
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;

Setelah mencoba banyak solusi. Ini berhasil untuk saya. Mungkin bisa membantu orang lain memposting. Dapat dari sini

Aniket Betkikar
sumber
0

Berikut adalah solusi yang disederhanakan (ini tidak bekerja dengan batas / pengguliran):

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

Saya sedang membuat aplikasi yang memiliki kanvas di atas pdf, yang melibatkan banyak ukuran kanvas seperti Memperbesar pdf-in dan out, dan pada gilirannya pada setiap zoom-in / out dari PDF saya harus mengubah ukuran kanvas untuk menyesuaikan ukuran pdf, saya melewati banyak jawaban di stackOverflow, dan tidak menemukan solusi sempurna yang pada akhirnya akan menyelesaikan masalah.

Saya menggunakan rxjs dan angular 6, dan tidak menemukan jawaban khusus untuk versi terbaru.

Berikut ini seluruh potongan kode yang akan membantu, bagi siapa pun yang memanfaatkan rxjs untuk menggambar di atas kanvas.

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

Dan di sini adalah potongan yang memperbaiki, koordinat mouse relatif terhadap ukuran kanvas, terlepas dari bagaimana Anda memperbesar / memperkecil kanvas.

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 )
};
Divyanshu Rawat
sumber
-1

Hei, ini di dojo, hanya karena itu yang sudah saya punya kode untuk sebuah proyek.

Seharusnya cukup jelas bagaimana mengubahnya kembali ke JavaScript non dojo vanilla.

  function onMouseClick(e) {
      var x = e.clientX;
      var y = e.clientY;
  }
  var canvas = dojo.byId(canvasId);
  dojo.connect(canvas,"click",onMouseClick);

Semoga itu bisa membantu.

Brian Gianforcaro
sumber
6
clientX / clientY tidak berlaku sama di seluruh browser.
tfwright