Bir tuval öğesine fare tıklamasının koordinatlarını nasıl alabilirim?


276

Bir tuval öğesine, tıklamanın x ve y koordinatlarını (tuval öğesine göre) döndürecek bir tıklama olay işleyicisi eklemenin en basit yolu nedir?

Eski tarayıcı uyumluluğu gerekmez, Safari, Opera ve Firefox bunu yapar.


Bu, normal dom öğelerinden fare olayları almaktan farklı olmamalıdır. quirksmode bu konuda iyi bir referansa sahiptir.
airportyh

4
Yukarıda listelediğiniz kod yalnızca tuval diğer kapların derinliklerinde olmadığında çalışır. Genel olarak jquery offset işlevi gibi bir şey kullanmanız gerekir [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] tarayıcılar arası doğru ofseti elde etmek için. Bu *** gerçek bir acı.
Aaron Watters

Tuvali içeren sayfa kaydırılırsa, yukarıda Update ile gönderilen kod çalışmaz.
Timothy Kim

Soruya güncelleme olarak dahil edilen eski "cevabımı" kaldırdım. Belirtildiği gibi, güncel ve eksikti.
Tom

3
Burada 50 cevap olduğu için, bu adamlara cevap vermenizi tavsiye ederim: patikler - iyi ve basit bir 5 astar.
Igor

Yanıtlar:


77

Düzenleme 2018: Bu cevap oldukça eskidir ve gibi, artık gerekli olmayan eski tarayıcılar için kontroller kullanır clientXve clientYözellikleri tüm güncel tarayıcılarda çalışır. Daha basit ve daha yeni bir çözüm için Patriques Answer'a göz atmak isteyebilirsiniz .

Orijinal cevap:
Bir makalede açıklandığı gibi, o zaman buldum ama artık mevcut değil:

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;

Benim için mükemmel çalıştı.


30
Bu çözüm her zaman işe yaramaz - Ryan Artecona'nın cevabı, tuvalin tüm sayfaya göre zorunlu olarak konumlandırılmadığı daha genel durumda çalışır.
Chris Johnson

3
Performans önemliyse bu çözüm takılmaz, çünkü her tıklama / harekette Dom erişimi yapılır. Ve getBoundingClientRect şimdi var ve daha zarif.
GameAlchemist

192

Basitliği seviyorsanız ancak yine de çapraz tarayıcı işlevselliği istiyorsanız, bu çözümün benim için en iyi sonuç verdiğini gördüm. Bu @ Aldekein'in çözümünün basitleştirilmesidir, ancak jQuery olmadan .

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

Sayfa aşağı kaydırılırsa, sanırım belgenin kaydırma ofsetini de dikkate almalısınız.
Peppe LG

8
@ PeppeL-G sınırlayıcı istemci dikdörtgen bunu sizin için hesaplar. Yorum göndermeden önce konsolda kolayca test edebilirsiniz (yaptığım budur).
Tomáš Zato - Monica'yı eski durumuna döndür

1
@ TomášZato, oh, getBoundingClientRectgörünüm bağlantı noktasına göre konumlar döndürüyor mu? Sonra tahminim yanlıştı. Bunu hiç test etmedim, çünkü bu benim için hiçbir zaman bir sorun değildi ve diğer okuyucuları gördüğüm potansiyel bir sorun hakkında uyarmak istedim, ama açıklaman için teşekkür ederim.
Peppe LG

1
Tuval ölçeklendirilirse bu çalışmaz. Bunun bir tarayıcı hatası olup olmadığından emin değilim.
Jeroen

2
Benim gibi biri için kullanım ekle:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion

179

Güncelleme (5/5/16): hem daha basit hem de daha güvenilir olduğu için patriklerin cevabı kullanılmalıdır.


Tuval her zaman tüm sayfaya göre şekillendirilmediğinden, canvas.offsetLeft/Topher zaman ihtiyacınız olanı döndürmez. OfsetParent öğesine göre ötelenen piksel sayısını döndürür; bu, stil uygulanmış divtuvali içeren bir öğe gibi olabilir position: relative. Bunu hesaba katmak için offsetParenttuval öğesinin kendisinden başlayarak s zincirinde döngü yapmanız gerekir . Bu kod benim için mükemmel çalışıyor, Firefox ve Safari'de test edildi, ancak herkes için çalışmalı.

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;

Son satır, bir tuval öğesine göre fare koordinatlarını elde etmek için işleri kolaylaştırır. Yararlı koordinatları elde etmek için gereken tek şey

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;

8
Hayır, yerleşik javascript prototip nesnesini kullanıyor --- developer.mozilla.org/en/…
garg

14
Chrome'umda event.offsetXve event.offsetYniteliklerim var, bu yüzden çözümünüzü ekleyerek değiştirdim if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. işe yarıyor gibi görünüyor.
Baczek

3
Baczek, Chrome9 için de doğru event.offsetXve IE9'da event.offsetYda çalışıyor. Firefox (v13 ile test edilmiş) için event.layerXve kullanabilirsiniz event.layerY.
mafafu

3
Bunu ayrıca ekledim: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc

4
Bu son cevap sürümü benim için çalışmadı. Firefox'ta, tüm ekran kaydırılırsa, yer değiştirilen değeri çıktı olarak aldım. Benim için işe yarayan, stackoverflow.com/a/10816667/578749'da event.pageX / Y yerine hesaplanan ofseti event.clientX / Y'den çıkardığına göre çok benzer bir çözümdü . Birisi bunu gözden geçirip açıklayabilir mi?
lvella

33

Modern tarayıcı şimdi bunu sizin için halleder. Chrome, IE9 ve Firefox, olayı tıklama işleyicisinden geçirerek offsetX / Y'yi bu şekilde destekler.

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

Çoğu modern tarayıcı da layerX / Y'yi destekler, ancak Chrome ve IE sayfa kenar boşluğu, dolgu vb. Dahil tıklamanın mutlak ofseti için layerX / Y kullanır, ancak Firefox'ta layerX / Y ve offsetX / Y eşdeğerdir, ancak ofset daha önce yok. Bu nedenle, biraz daha eski tarayıcılarla uyumluluk için şunları kullanabilirsiniz:

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

1
layerX, layerY'nin hem Chrome hem de Firefox'ta nasıl tanımlandığı ilginç, ancak Chrome'da yanlış (veya başka bir şey anlamına geliyor).
Julian Mann

@JulianMann Bilgi için teşekkürler. Bu yanıtı daha güncel desteğe dayanarak güncelledim. Neredeyse evrensel olarak offsetX / Y ile kurtulabileceğiniz anlaşılıyor.
mafafu

18

Taze göre QuirksmodeclientX ve clientYyöntemler tüm büyük tarayıcılar tarafından desteklenir. Yani, işte gidiyor - kaydırma çubuklu bir sayfada kaydırma divında çalışan iyi, çalışan kod:

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

Bu aynı zamanda gerektirir jQuery için $(canvas).offset().


@ N4ppeL cevabına eşdeğerdir.
Paweł Szczur


11

Değişken (%) genişliğe sahip tuvaller için Ryan Artecona'nın cevabında küçük bir değişiklik :

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

7

Koordinat dönüşümü yaparken dikkatli olun; bir tıklama etkinliğinde döndürülen birden çok tarayıcı olmayan değer vardır. Tarayıcı penceresi kaydırılırsa (Firefox 3.5 ve Chrome 3.0'da doğrulanırsa) yalnızca clientX ve clientY kullanmak yeterli değildir.

Bu ilginç mod makalesi, belge kaynağına göre tıklama koordinatını hesaplamak için pageX veya pageY ya da clientX ile document.body.scrollLeft ve clientY ile document.body.scrollTop komutlarını kullanabilen daha doğru bir işlev sağlar.

GÜNCELLEME: Ayrıca, offsetLeft ve offsetTop öğesi, iç boyutla değil, öğenin yastıklı boyutuyla ilgilidir. Dolgu: stil uygulanmış bir tuval, içerik bölgesinin sol üst kısmını offsetLeft olarak bildirmez. Bu sorunun çeşitli çözümleri vardır; en basit olanı, tuval üzerindeki tüm kenarlık, dolgu vb. stillerini temizlemek ve bunun yerine tuvali içeren bir kutuya uygulamak olabilir.


7

Ebeveyn öğeler arasında dolaşan ve her türlü garip şeyler yapan tüm bu cevapların ne anlama geldiğinden emin değilim .

HTMLElement.getBoundingClientRectYöntem herhangi bir elemanın gerçek ekran konumunu işlemek için dizayn edilmiştir. Bu kaydırma içerir, bu yüzden scrollTopgerekli olan şeylere gerek yoktur:

(MDN'den) Sınırlayıcı dikdörtgeni hesaplarken, görünüm alanı (veya başka bir kaydırılabilir öğe ) üzerindeyapılan kaydırma miktarı dikkate alınır.

Normal görüntü

En basit yaklaşım zaten burada yayınlanmıştır. Hiçbir vahşi CSS kuralı bulunmadığı sürece bu doğrudur .

Gerilmiş tuval / görüntüyü kullanma

Resim piksel genişliği CSS genişliği ile eşleşmediğinde, piksel değerlerine bir oran uygulamanız gerekir:

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

Tuvalin kenarlığı olmadığı sürece, gergin görüntüler için çalışır (jsFiddle) .

CSS kenarlıklarını işleme

Tuvalin kalın kenarlığı varsa, işler biraz karmaşıklaşır . Kelimenin tam anlamıyla kenarlığı sınırlayıcı dikdörtgenden çıkarmanız gerekir. Bu, .getComputedStyle kullanılarak yapılabilir . Bu cevap süreci açıklar .

Fonksiyon daha sonra biraz büyür:

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

Bu son işlevi karıştıracak hiçbir şey düşünemiyorum. Kendinizi JsFiddle'da görün .

notlar

Yerel ayarları değiştirmekten hoşlanmıyorsanız prototype, sadece işlevi değiştirin ve ile çağırın (canvas, event)(ve herhangi birini thisile değiştirin canvas).


6

İşte çok güzel bir eğitim-

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

Bu yardımcı olur umarım!


Ryan Artecona'nın çözümü zumlu tablet tarayıcılarda işe yaramadı. Ancak bunu yaptı.
Andy Meyers

CSS width/ heightgeçersiz kılınmış, ancak yine de en iyi çözümlerden biri olan görüntülerle çalışmaz .
Tomáš Zato - Monica'yı eski durumuna döndür

3

Tuvale göre tıklama koordinatlarını almak için 2016'da jQuery kullanarak şunu yaparım:

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

Bu, hem tuval ofseti () hem de jqEvent.pageX / Y, kaydırma konumundan bağımsız olarak belgeye göreli olduğundan çalışır.

Tuvaliniz ölçeklendirilmişse, bu koordinatların tuval mantıksal koordinatlarıyla aynı olmadığını unutmayın . Bunları almak için şunları da yapardınız:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}

Vay. 'JqEvent' nasıl tanımlanır? Yoksa 'tuval' mi? Veya ikinci örnekte 'koordinatlar'? İlk örneği ikinciden önce çalıştırmanız mı gerekiyor? Bu durumda, neden "almak için, sen de yapsın" yazmıyorsun? Bunların hepsi bir tıklama fonksiyonuna mı giriyor? Biraz bağlam ver dostum. Ve 2008'de sorulan orijinal soru dikkate alındığında, 2008'de mevcut olan teknoloji bağlamında cevaplamanız gerektiğini düşünüyorum. O zaman mevcut olan sürümden geçerli sürüm (j1.2) kullanarak cevabınızı hassaslaştırın. ;)
Ayelis

1
Tamam, küstahlığım için üzgünüm. Bunu kaldırmak için düzenleyeceğim. En son çerçeveleri kullanarak cevap vermeyi planladım. Ve bir programcının jqEvent, canvas ve coord'ların ne olduğunu açıklamasına gerek olmadığını düşünüyorum.
Sarsaparilla

İyi görünüyor. Girdiniz için teşekkürler! Üzgünüm sana zor zamanlar verdim! ;)
Ayelis

3

Yani bu hem basit hem de göründüğünden biraz daha karmaşık bir konu.

Öncelikle burada genellikle kapalı sorular var

  1. Eleman göreli fare koordinatları nasıl edinilir

  2. 2D Tuval API veya WebGL için tuval piksel fare koordinatları nasıl elde edilir

yani cevaplar

Eleman göreli fare koordinatları nasıl edinilir

Öğenin bir tuval elde etme öğesi olup olmadığı, göreli fare koordinatları tüm öğeler için aynıdır.

"Tuval bağıl fare koordinatları nasıl alınır" sorusuna 2 basit cevap vardır.

Basit cevap # 1 kullanımı offsetXveoffsetY

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

Bu yanıt Chrome, Firefox ve Safari'de çalışır. Diğer tüm etkinlik değerlerinin aksine offsetXve offsetYdikkate almak CSS dönüştürmeleri.

İle en büyük sorun offsetXve offsetYonlar dokunma etkinliklerine yoktur ve bu yüzden iOS Safari ile kullanılamaz 2019/05 itibariyledir. Görünüşe göre Safari üzerinde çalışmasına rağmen, Chrome ve Firefox'ta bulunan ancak Safari'de bulunmayan Pointer Etkinliklerinde varlar .

Başka bir sorun da olayların tuval üzerinde olması gerektiğidir. Bunları başka bir öğeye veya pencereye koyarsanız, daha sonra referans noktanız olarak tuvali seçemezsiniz.

Cevap basit 2. kullanımı clientX, clientYvecanvas.getBoundingClientRect

Eğer CSS dönüştürmeleri umurumda değil ise bir sonraki en basit cevap aramaktır canvas. getBoundingClientRect()ve çıkarma soldan clientXve topgelen clientYgibi

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

Bu, CSS dönüşümü olmadığı sürece çalışacaktır. Ayrıca dokunmatik etkinliklerle çalışır ve bu yüzden Safari iOS ile çalışır

canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});

2D Canvas API'sı için canvas pixel mouse koordinatları nasıl edinilir

Bunun için yukarıda aldığımız değerleri almalıyız ve kanvasın görüntülendiği boyuttan kanvastaki piksel sayısına dönüştürmeliyiz.

ile canvas.getBoundingClientRectve clientXveclientY

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

veya birlikte offsetXveoffsetY

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

Not: Her durumda, tuvale dolgu veya kenarlık eklemeyin. Bunu yapmak kodu büyük ölçüde karmaşıklaştıracaktır. Bunun yerine, başka bir öğede tuvali çevreleyen bir kenarlık veya dolgu ve dış öğeye dolgu ve / veya kenarlık ekleyin.

Kullanarak çalışma örneği event.offsetX,event.offsetY

Kullanılarak örnek çalışma canvas.getBoundingClientRectve event.clientXveevent.clientY


2

Bu bağlantıyı öneririm- 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>

amacı x = new Number()nedir? Yeniden atanan aşağıdaki kod x, tahsis edilen
Sayının


1

Sadece şunları yapabilirsiniz:

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

Bu size fare işaretçisinin tam konumunu verecektir.


1

Demoyu http://jsbin.com/ApuJOSA/1/edit?html,output adresinde görebilirsiniz .

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

0

Yukarıdaki Ryan Artecona çözümünün bazı modifikasyonları.

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

0

İlk olarak, diğerlerinin söylediği gibi, tuval öğesinin konumunu almak için bir işleve ihtiyacınız vardır . İşte bu sayfadaki diğerlerinden (IMHO) biraz daha zarif bir yöntem. Herhangi bir öğeyi iletebilir ve belgedeki konumunu alabilirsiniz:

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

Şimdi imlecin şu anki konumunu hesaplayın:

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

Genel findPosişlevi olay işleme kodundan ayırdım dikkat edin . ( Olması gerektiği gibi . İşlevlerimizi her biri bir görevde tutmaya çalışmalıyız.)

Değerleri offsetLeftve offsetTopgöredir offsetParentbazı sarıcı olabilir ki, div(bu konuda veya başka bir şey,) düğümü. Kaydıran bir öğe olmadığında, canvasbunlar görecelidir body, bu nedenle çıkarılacak ofset yoktur. Bu yüzden başka bir şey yapmadan önce tuvalin konumunu belirlememiz gerekiyor.

Benzer şekilde e.pageXvee.pageY imlecin belgeye göre konumunu da verin. Bu yüzden tuvalin ofsetini gerçek konuma ulaşmak için bu değerlerden çıkarırız.

Konumlandırılmış elemanlar için bir alternatif e.layerXve ve değerlerini doğrudan kullanmaktır e.layerY. Bu, iki nedenden dolayı yukarıdaki yöntemden daha az güvenilirdir:

  1. Bu değerler, olay konumlandırılmış bir öğenin içinde gerçekleşmediğinde tüm belgeye göredir
  2. Bunlar herhangi bir standardın parçası değildir

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;

Birçok çözüm denedikten sonra. Bu benim için çalıştı. Başka birisinin yayın yapmasına yardımcı olabilir. Buradan anladım


0

İşte basitleştirilmiş bir çözüm (bu kenarlıklar / kaydırma ile çalışmaz):

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

0

Bir pdf üzerinde tuvale sahip bir uygulama oluşturuyordum , pdf-in ve out Yakınlaştırma gibi bir çok tuval boyutlarını içeriyordu ve PDF'nin her yakınlaştırma / uzaklaştırma özelliğini etkinleştirmek için tuvali yeniden boyutlandırmak zorunda kaldım pdf boyutunda, stackOverflow'da çok fazla cevap aldım ve sonunda sorunu çözecek mükemmel bir çözüm bulamadım.

Rxjs ve açısal 6 kullanıyordum ve en yeni sürüme özgü bir cevap bulamadım.

İşte tuval üzerine çizmek için rxjs kullanan herkese yardımcı olacak tüm kod snippet'i .

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

Ve tuvali nasıl büyüttüğünüze / uzaklaştırdığınıza bakılmaksızın, tuval boyutuna göre fare koordinatlarını sabitleyen snippet.

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

-1

Hey, bu dojo'da, çünkü zaten bir proje için kodum vardı.

Dojo olmayan vanilya JavaScript'e nasıl dönüştürüleceği oldukça açık olmalıdır.

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

Umarım yardımcı olur.


6
clientX / clientY tarayıcılarda benzer şekilde davranmaz.
tfwright
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.