Come posso ottenere le coordinate di un clic del mouse su un elemento canvas?


276

Qual è il modo più semplice per aggiungere un gestore di eventi click a un elemento canvas che restituirà le coordinate xey del clic (rispetto all'elemento canvas)?

Non è richiesta la compatibilità del browser legacy, Safari, Opera e Firefox lo faranno.


Questo non dovrebbe essere diverso dall'ottenere eventi del mouse da normali elementi dom. quirksmode ha un buon riferimento su questo.
airportyh,

4
Il codice che elenchi sopra funziona solo quando la tela non è in profondità all'interno di altri contenitori. In generale devi usare qualcosa come la funzione offset jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] per ottenere l'offset corretto in un browser incrociato. Questo è un vero dolore nel ***.
Aaron Watters,

Il codice pubblicato sopra con Aggiornamento non funziona se la pagina contenente le aree di scorrimento scorre.
Timothy Kim,

Ho rimosso la mia vecchia "risposta" che è stata inclusa come aggiornamento alla domanda. Come accennato, era obsoleto e incompleto.
Tom,

3
Dato che ci sono circa 50 risposte qui, raccomando di scorrere fino a questa risposta di ragazzi: patriques - un buon e semplice 5 liner.
Igor L.,

Risposte:


77

Modifica 2018: questa risposta è piuttosto vecchia e utilizza i controlli per i vecchi browser che non sono più necessari, poiché le proprietà clientXe clientYfunzionano in tutti i browser correnti. Potresti voler controllare Patriques Answer per una soluzione più semplice e più recente.

Risposta originale:
Come descritto in un articolo che ho trovato allora ma non esiste più:

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;

Ha funzionato perfettamente bene per me.


30
Questa soluzione non sempre funziona: la risposta di Ryan Artecona funziona nel caso più generale quando la tela non è necessariamente posizionata rispetto all'intera pagina.
Chris Johnson,

3
Questa soluzione non è adatta se le prestazioni sono importanti, poiché l'accesso a Dom viene eseguito su ogni clic / spostamento. E getBoundingClientRect esiste ora ed è più elegante.
GameAlchemist

192

Se ti piace la semplicità ma desideri comunque la funzionalità cross-browser, ho scoperto che questa soluzione ha funzionato meglio per me. Questa è una semplificazione della soluzione di @Aldekein ma senza 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)
})

Se la pagina viene spostata verso il basso, suppongo che si dovrebbe prendere in considerazione anche l'offset di scorrimento del documento.
Peppe LG,

8
Il rettangolo del client di delimitazione di @ PeppeL-G calcola quello per te. Puoi facilmente provarlo in console prima di pubblicare un commento (è quello che ho fatto).
Tomáš Zato - Ripristina Monica il

1
@ TomášZato, oh, getBoundingClientRectrestituisce le posizioni relative alla porta di visualizzazione? Quindi la mia ipotesi era sbagliata. Non l'ho mai provato dal momento che questo non è mai stato un problema per me e ho gentilmente voluto avvisare gli altri lettori di un potenziale problema che ho visto, ma grazie per il vostro chiarimento.
Peppe LG,

1
Questo non funziona se la tela viene ridimensionata. Non sono sicuro se si tratta di un bug del browser.
Jeroen,

2
Aggiungi utilizzo per qualcuno come me:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion,

179

Aggiornamento (5/5/16): si dovrebbe usare invece la risposta dei brevetti , poiché è sia più semplice che più affidabile.


Poiché la tela non è sempre in stile rispetto all'intera pagina, canvas.offsetLeft/Topnon restituisce sempre ciò di cui hai bisogno. Restituirà il numero di pixel di cui è sfalsato rispetto al suo elemento offsetParent, che può essere qualcosa di simile a un divelemento contenente la tela con uno position: relativestile applicato. Per tener conto di ciò, è necessario scorrere la catena di offsetParents, iniziando con l'elemento canvas stesso. Questo codice funziona perfettamente per me, testato in Firefox e Safari ma dovrebbe funzionare per tutti.

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;

L'ultima riga rende le cose convenienti per ottenere le coordinate del mouse relative a un elemento canvas. Tutto ciò che serve per ottenere le coordinate utili è

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

8
No, utilizza l'oggetto prototipo javascript incorporato --- developer.mozilla.org/it/…
garg

14
il mio Chrome ha event.offsetXe event.offsetYattributi, quindi ho modificato la tua soluzione aggiungendo if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. sembra che funzioni.
Baczek,

3
Baczek ha ragione su Chrome event.offsetXe event.offsetYfunziona anche su IE9. Per Firefox (testato w / v13) è possibile utilizzare event.layerXe event.layerY.
mafafu,

3
Ho aggiunto anche questo: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc,

4
Questa versione finale sulla risposta non ha funzionato per me. Su Firefox, se si scorre l'intero schermo, ho ottenuto il valore spostato come output. Che cosa ha funzionato per me era una soluzione molto simile, dato lo stackoverflow.com/a/10816667/578749 che, invece di event.pageX / Y, è sottratto calcolato compensata da event.clientX / Y. Qualcuno potrebbe rivedere questo e spiegare?
lvella,

33

Il browser moderno ora gestisce questo per te. Chrome, IE9 e Firefox supportano offsetX / Y in questo modo, passando l'evento dal gestore di clic.

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

La maggior parte dei browser moderni supporta anche layerX / Y, tuttavia Chrome e IE utilizzano layerX / Y per l'offset assoluto del clic sulla pagina inclusi margine, riempimento, ecc. In Firefox, layerX / Y e offsetX / Y sono equivalenti, ma offset non ha non esisteva in precedenza. Quindi, per compatibilità con browser leggermente più vecchi, puoi usare:

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

1
interessante come layerX, layerY sia definito su Chrome e Firefox, ma su Chrome non è preciso (o significa qualcos'altro).
Julian Mann,

@JulianMann Grazie per le informazioni. Ho aggiornato questa risposta in base al supporto più attuale. Sembra che tu possa scappare con offsetX / Y quasi universalmente ora.
mafafu,

18

Secondo la nuova modalità Quirks, i metodi clientXe clientYsono supportati in tutti i principali browser. Quindi, ecco qui - il buon codice funzionante che funziona in un div a scorrimento su una pagina con barre di scorrimento:

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

Ciò richiede anche jQuery per $(canvas).offset().


Equivalente alla risposta @ N4ppeL.
Paweł Szczur,


11

Ecco una piccola modifica alla risposta di Ryan Artecona per le tele con una larghezza (%) variabile:

 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

Diffidare mentre si esegue la conversione delle coordinate; ci sono più valori non cross-browser restituiti in un evento click. L'uso di clientX e clientY da soli non è sufficiente se si scorre la finestra del browser (verificato in Firefox 3.5 e Chrome 3.0).

Questo articolo in modalità strane fornisce una funzione più corretta che può utilizzare pageX o pageY o una combinazione di clientX con document.body.scrollLeft e clientY con document.body.scrollTop per calcolare la coordinata dei clic relativa all'origine del documento.

AGGIORNAMENTO: Inoltre, offsetLeft e offsetTop sono relativi alla dimensione imbottita dell'elemento, non alla dimensione interna. Una tela con il riempimento: lo stile applicato non riporterà in alto a sinistra la sua area di contenuto come offsetLeft. Esistono varie soluzioni a questo problema; il più semplice potrebbe essere quello di cancellare tutti gli stili di bordo, imbottitura, ecc. sulla tela stessa e applicarli invece a una scatola contenente la tela.


7

Non sono sicuro di quale sia il punto di tutte queste risposte che attraversano gli elementi principali e fanno tutti i tipi di cose strane .

Il HTMLElement.getBoundingClientRectmetodo è progettato per gestire la posizione effettiva dello schermo di qualsiasi elemento. Questo include lo scorrimento, quindi cose come scrollTopnon sono necessarie:

(da MDN) La quantità di scorrimento che è stata effettuata nell'area della finestra (o qualsiasi altro elemento scorrevole ) viene presa in considerazione quando si calcola il rettangolo di delimitazione

Immagine normale

L' approccio più semplice era già stato pubblicato qui. Ciò è corretto purché non siano coinvolte regole CSS selvatiche .

Gestione di tela / immagine allungate

Quando la larghezza del pixel dell'immagine non corrisponde alla sua larghezza CSS, dovrai applicare un rapporto sui valori dei pixel:

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

Finché la tela non ha bordi, funziona per le immagini allungate (jsFiddle) .

Gestione dei bordi CSS

Se la tela ha bordi spessi, le cose si complicano un po ' . Dovrai letteralmente sottrarre il bordo dal rettangolo di delimitazione. Questo può essere fatto usando .getComputedStyle . Questa risposta descrive il processo .

La funzione quindi cresce un po ':

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

Non riesco a pensare a nulla che possa confondere questa funzione finale. Guardati su JsFiddle .

Appunti

Se non ti piace modificare i nativi prototype, basta cambiare la funzione e chiamarla con (canvas, event)(e sostituirla thiscon canvas).


6

Ecco un bellissimo tutorial-

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

spero che questo ti aiuti!


La soluzione di Ryan Artecona non ha funzionato per i browser tablet con zoom. Tuttavia, questo ha fatto.
Andy Meyers,

Non funziona con immagini che hanno CSS width/ heightoverriden ma è comunque una delle migliori soluzioni.
Tomáš Zato - Ripristina Monica il

3

Utilizzando jQuery nel 2016, per ottenere le coordinate dei clic relative all'area di lavoro, faccio:

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

Funziona poiché sia ​​offset tela () che jqEvent.pageX / Y sono relativi al documento indipendentemente dalla posizione di scorrimento.

Nota che se la tua tela è ridimensionata, queste coordinate non sono le stesse delle coordinate logiche della tela . Per ottenerli, dovresti anche :

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

Wow. Come viene definito 'jqEvent'? O 'tela'? O nel secondo esempio "coords"? Devi eseguire il primo esempio prima del secondo? In tal caso, perché non dovresti scrivere "per ottenerli, lo faresti ANCHE"? Tutto questo va in una funzione onclick o cosa? Dai un piccolo contesto, amico. E considerando che la domanda originale è stata posta nel 2008, penso che tu debba rispondere nel contesto della tecnologia che era disponibile nel 2008. Affina la tua risposta usando jQuery valido dalla versione che era disponibile al momento (v1.2). ;)
Ayelis,

1
OK, scusa per la presunzione. Modificherò per rimuovere quello. Ho intenzione di fornire la risposta utilizzando i framework più recenti. E credo che un programmatore non avrebbe bisogno di essere spiegato cosa sono jqEvent, canvas e coords.
Sarsaparilla,

Sembra buono. Grazie per il tuo contributo! Mi dispiace di averti dato un momento difficile! ;)
Ayelis,

3

Quindi questo è un argomento semplice ma leggermente più complicato di quanto sembri.

Prima di tutto ci sono di solito domande confuse qui

  1. Come ottenere le coordinate del mouse relative agli elementi

  2. Come ottenere le coordinate del mouse pixel dell'area di disegno per l'API 2D Canvas o WebGL

così, risposte

Come ottenere le coordinate del mouse relative agli elementi

Indipendentemente dal fatto che l'elemento sia un'area di disegno che ottiene le coordinate relative del mouse dell'elemento è uguale per tutti gli elementi.

Ci sono 2 semplici risposte alla domanda "Come ottenere le coordinate del mouse relative alla tela"

Risposta semplice n. 1 uso offsetXeoffsetY

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

Questa risposta funziona in Chrome, Firefox e Safari. A differenza di tutti gli altri valori di eventi offsetXe offsetYprendere in considerazione le trasformazioni CSS.

Il problema più grande con offsetXed offsetYè dal 2019/05 non esistono su eventi touch e quindi non possono essere utilizzati con iOS Safari. Esistono su eventi puntatore che esistono in Chrome e Firefox ma non in Safari, anche se apparentemente Safari ci sta lavorando .

Un altro problema è che gli eventi devono essere sulla stessa tela. Se li metti su qualche altro elemento o sulla finestra non puoi in seguito scegliere la tela come punto di riferimento.

Risposta semplice # 2 uso clientX, clientYecanvas.getBoundingClientRect

Se non ti interessano le trasformazioni CSS, la prossima risposta più semplice è chiamare canvas. getBoundingClientRect()e sottrarre la sinistra da clientXe topda clientYcome in

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

Funzionerà finché non ci sono trasformazioni CSS. Funziona anche con eventi touch e quindi funziona con 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;
});

Come ottenere le coordinate del mouse pixel dell'area di disegno per l'API Canvas 2D

Per questo abbiamo bisogno di prendere i valori che abbiamo sopra e convertire dalla dimensione della tela visualizzata al numero di pixel nella tela stessa

con canvas.getBoundingClientRecte clientXeclientY

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

o con offsetXeoffsetY

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

Nota: in tutti i casi non aggiungere imbottitura o bordi alla tela. Ciò potrebbe complicare enormemente il codice. Invece di te vuoi un bordo o un'imbottitura che circonda la tela in qualche altro elemento e aggiungi l'imbottitura o il bordo all'elemento esterno.

Esempio funzionante usando event.offsetX,event.offsetY

Esempio di lavoro usando canvas.getBoundingClientRecte event.clientXeevent.clientY


2

Consiglio questo link: 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>

che senso ha x = new Number()? Il codice in basso che riassegna il xche significa che il numero assegnato viene immediatamente scartato
gman


1

Potresti semplicemente fare:

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

Questo ti darà la posizione esatta del puntatore del mouse.


1

Guarda la demo su 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 };
  }

0

Ecco alcune modifiche della soluzione di Ryan Artecona sopra.

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

Innanzitutto, come altri hanno già detto, è necessaria una funzione per ottenere la posizione dell'elemento canvas . Ecco un metodo un po 'più elegante di alcuni degli altri in questa pagina (IMHO). Puoi passargli qualsiasi elemento e ottenere la sua posizione nel documento:

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

Ora calcola la posizione corrente del cursore rispetto a quella:

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

Si noti che ho separato la findPosfunzione generica dal codice di gestione degli eventi. ( Come dovrebbe essere . Dovremmo cercare di mantenere le nostre funzioni per un compito ciascuno.)

I valori di offsetLeft e offsetTopsono relativi a offsetParent, che potrebbe essere un divnodo wrapper (o qualsiasi altra cosa, del resto). Quando non è presente alcun elemento a capo canvas, sono relativi a body, quindi non vi è alcun offset da sottrarre. Questo è il motivo per cui dobbiamo determinare la posizione della tela prima di poter fare qualsiasi altra cosa.

Simile e.pageXe indica e.pageYla posizione del cursore rispetto al documento. Ecco perché sottraggiamo l'offset della tela da quei valori per arrivare alla posizione reale.

Un'alternativa per elementi posizionati è utilizzare direttamente i valori di e.layerXe e.layerY. Questo è meno affidabile del metodo sopra per due motivi:

  1. Questi valori sono anche relativi all'intero documento quando l'evento non ha luogo all'interno di un elemento posizionato
  2. Non fanno parte di alcuno standard

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;

Dopo aver provato molte soluzioni. Questo ha funzionato per me. Potrebbe aiutare qualcun altro a postare. Capito da qui


0

Ecco una soluzione semplificata (non funziona con bordi / scorrimento):

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

Stavo creando un'applicazione con una tela su un pdf, che comportava molti ridimensionamenti della tela come Zoomare il PDF in e out, e a sua volta ogni zoom in / out del PDF dovevo ridimensionare la tela per adattare il dimensione del pdf, ho esaminato molte risposte in stackOverflow e non ho trovato una soluzione perfetta che alla fine risolverà il problema.

Stavo usando rxjs e angular 6 e non ho trovato alcuna risposta specifica alla versione più recente.

Ecco l'intero snippet di codice che sarebbe utile a chiunque sfrutti rxjs per disegnare sulla tela.

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

Ed ecco lo snippet che corregge, coordinate del mouse relative alla dimensione della tela, indipendentemente da come si ingrandisce / rimpicciolisce la tela.

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

Ehi, questo è nel dojo, solo perché è quello in cui avevo già il codice per un progetto.

Dovrebbe essere abbastanza ovvio come riconvertirlo in 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);

Spero che aiuti.


6
clientX / clientY non si comportano in modo simile tra i browser.
tfwright,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.