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

StackOverflow https://stackoverflow.com/questions/55677

  •  09-06-2019
  •  | 
  •  

Domanda

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

Non è richiesta la compatibilità con browser legacy, Safari, Opera e Firefox andranno bene.

È stato utile?

Soluzione

Modifica 2018: Questa risposta è piuttosto vecchia e utilizza controlli per i vecchi browser che non sono più necessari, come il file clientX E clientY le proprietà funzionano in tutti i browser attuali.Potresti voler dare un'occhiata La risposta di Patrizio per una soluzione più semplice e più recente.

Risposta originale:
Come descritto in un articolo che trovai allora ma che 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 per me.

Altri suggerimenti

Aggiornamento (5/5/16): la risposta di Patrizio dovrebbe essere usato invece, poiché è più semplice e più affidabile.


Poiché lo stile della tela non è sempre relativo all'intera pagina, il file canvas.offsetLeft/Top non sempre restituisce ciò di cui hai bisogno.Restituirà il numero di pixel di cui è offset rispetto al suo elemento offsetParent, che può essere qualcosa come a div elemento contenente la tela con a position: relative stile applicato.Per tenere conto di ciò è necessario eseguire il ciclo attraverso la catena di offsetParents, a cominciare dall'elemento canvas stesso.Questo codice funziona perfettamente per me, testato su 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 della tela.Tutto ciò che serve per ottenere le coordinate utili è

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

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) {
    var rect = canvas.getBoundingClientRect();
    var x = event.clientX - rect.left;
    var y = event.clientY - rect.top;
    console.log("x: " + x + " y: " + y);
}

I browser moderni ora gestiscono questo per te.Chrome, IE9 e Firefox supportano l'offsetX/Y in questo modo, passando l'evento dal gestore dei clic.

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

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

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

Secondo fresco Modalità stranezze IL clientX E clientY i metodi sono supportati in tutti i principali browser.Quindi eccolo qui: il codice valido e 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];
}

Anche questo richiede jQuery per $(canvas).offset().

Ho fatto una dimostrazione completa che funziona in ogni browser con il codice sorgente completo della soluzione di questo problema: Coordinate di un clic del mouse su Canvas in Javascript.Per provare la demo, copia il codice e incollalo in un editor di testo.Quindi salvalo come esempio.html e, infine, apri il file con un browser.

Ecco una piccola modifica a La risposta di Ryan Artecona per tele con 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}
}

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

Questa modalità stranezze articolo 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 del 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 l'imbottitura:lo stile applicato non riporterà la parte superiore sinistra dell'area del contenuto come offsetLeft.Esistono varie soluzioni a questo problema;il più semplice potrebbe essere quello di cancellare tutto il bordo, il riempimento, ecc.stili sulla tela stessa e applicarli invece a una casella contenente la tela.

Non sono sicuro quale sia il punto di tutte queste risposte scorrere gli elementi principali e fare di tutto cose strane.

IL HTMLElement.getBoundingClientRect Il metodo è progettato per gestire la posizione effettiva sullo schermo di qualsiasi elemento.Ciò include lo scorrimento, quindi cose del genere scrollTop non è necessario:

(da MDN) La quantità di scorrimento effettuato nell'area del viewport (o qualsiasi altro elemento scorrevole) viene preso in considerazione quando si calcola il rettangolo di delimitazione

Immagine normale

IL approccio molto più semplice era già stato pubblicato qui.Questo è corretto purché nessun CSS selvaggio sono coinvolte le regole.

Manipolazione di tele/immagini allungate

Quando la larghezza dei pixel dell'immagine non corrisponde alla 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 con immagini allungate (jsFiddle).

Gestione dei bordi CSS

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

La funzione poi 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.Ci vediamo a JsFiddle.

Appunti

Se non ti piace modificare il file native prototypes, basta cambiare la funzione e chiamarla con (canvas, event) (e sostituisci qualsiasi this con canvas).

Ecco un tutorial molto carino-

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!

Utilizzando jQuery nel 2016, per ottenere le coordinate dei clic relative alla tela, faccio:

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

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

Tieni presente che se la tua tela è ridimensionata, queste coordinate non sono le stesse della tela coordinate logiche.Per ottenerli, lo faresti Anche Fare:

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

Raccomando questo collegamento-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>

In Prototype, utilizza cumulativeOffset() per eseguire la somma ricorsiva come menzionato sopra da Ryan Artecona.

http://www.prototypejs.org/api/element/cumulativeoffset

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.

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

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

Prima di tutto qui di solito ci sono domande confuse

  1. Come ottenere le coordinate relative del mouse dell'elemento

  2. Come ottenere le coordinate del mouse pixel della tela per l'API 2D Canvas o WebGL

quindi, risposte

Come ottenere le coordinate relative del mouse dell'elemento

Il fatto che l'elemento sia o meno una tela che ottiene le coordinate relative del mouse dell'elemento è lo stesso per tutti gli elementi.

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

Risposta semplice n. 1 utilizzo offsetX E offsetY

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 evento offsetX E offsetY prendere in considerazione le trasformazioni CSS.

Il problema più grande con offsetX E offsetY a partire dal 2019/05 non esistono sugli 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 a quanto pare Safari ci sta lavorando.

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

Risposta semplice n. 2 utilizzo clientX, clientY E canvas.getBoundingClientRect

Se non ti interessano le trasformazioni CSS, la risposta più semplice successiva è chiamare canvas. getBoundingClientRect() e sottrai la sinistra da clientX E top da clientY come 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 saranno trasformazioni CSS.Funziona anche con eventi touch e quindi funzionerà 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 della tela per l'API 2D Canvas

Per questo dobbiamo prendere i valori che abbiamo ottenuto sopra e convertirli dalla dimensione visualizzata sulla tela al numero di pixel nella tela stessa

con canvas.getBoundingClientRect E clientX E clientY

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 offsetX E offsetY

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ò complicherebbe enormemente il codice.Invece di volere che un bordo o un'imbottitura circondino la tela in qualche altro elemento e aggiungino l'imbottitura e/o il bordo all'elemento esterno.

Esempio di lavoro utilizzando event.offsetX, event.offsetY

[...document.querySelectorAll('canvas')].forEach((canvas) => {
  const ctx = canvas.getContext('2d');
  ctx.canvas.width  = ctx.canvas.clientWidth;
  ctx.canvas.height = ctx.canvas.clientHeight;
  let count = 0;

  function draw(e, radius = 1) {
    const pos = {
      x: e.offsetX * canvas.width  / canvas.clientWidth,
      y: e.offsetY * canvas.height / canvas.clientHeight,
    };
    document.querySelector('#debug').textContent = count;
    ctx.beginPath();
    ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
    ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
    ctx.fill();
  }

  function preventDefault(e) {
    e.preventDefault();
  }

  if (window.PointerEvent) {
    canvas.addEventListener('pointermove', (e) => {
      draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
    });
    canvas.addEventListener('touchstart', preventDefault, {passive: false});
    canvas.addEventListener('touchmove', preventDefault, {passive: false});
  } else {
    canvas.addEventListener('mousemove', draw);
    canvas.addEventListener('mousedown', preventDefault);
  }
});

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
  width: 200px;
  height: 200px;
  perspective: 600px;
}

.cube {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  animation-duration: 16s;
  animation-name: rotate;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

@keyframes rotate {
  from { transform: translateZ(-100px) rotateX(  0deg) rotateY(  0deg); }
  to   { transform: translateZ(-100px) rotateX(360deg) rotateY(720deg); }
}

.cube__face {
  position: absolute;
  width: 200px;
  height: 200px;
  display: block;
}

.cube__face--front  { background: rgba(255, 0, 0, 0.2); transform: rotateY(  0deg) translateZ(100px); }
.cube__face--right  { background: rgba(0, 255, 0, 0.2); transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back   { background: rgba(0, 0, 255, 0.2); transform: rotateY(180deg) translateZ(100px); }
.cube__face--left   { background: rgba(255, 255, 0, 0.2); transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top    { background: rgba(0, 255, 255, 0.2); transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { background: rgba(255, 0, 255, 0.2); transform: rotateX(-90deg) translateZ(100px); }
<div class="scene">
  <div class="cube">
    <canvas class="cube__face cube__face--front"></canvas>
    <canvas class="cube__face cube__face--back"></canvas>
    <canvas class="cube__face cube__face--right"></canvas>
    <canvas class="cube__face cube__face--left"></canvas>
    <canvas class="cube__face cube__face--top"></canvas>
    <canvas class="cube__face cube__face--bottom"></canvas>
  </div>
</div>
<pre id="debug"></pre>

Esempio di lavoro utilizzando canvas.getBoundingClientRect E event.clientX E event.clientY

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.canvas.width  = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;

function draw(e, radius = 1) {
  const rect = canvas.getBoundingClientRect();
  const pos = {
    x: (e.clientX - rect.left) * canvas.width  / canvas.clientWidth,
    y: (e.clientY - rect.top) * canvas.height / canvas.clientHeight,
  };
  ctx.beginPath();
  ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
  ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
  ctx.fill();
}

function preventDefault(e) {
  e.preventDefault();
}

if (window.PointerEvent) {
  canvas.addEventListener('pointermove', (e) => {
    draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
  });
  canvas.addEventListener('touchstart', preventDefault, {passive: false});
  canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mousedown', preventDefault);
}

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
canvas { background: #FED; }
<canvas width="400" height="100" style="width: 300px; height: 200px"></canvas>
<div>canvas deliberately has differnt CSS size vs drawingbuffer size</div>

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.

Ecco alcune modifiche della soluzione di Ryan Artecona di cui 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};
}

Innanzitutto, come altri hanno già detto, è necessaria una funzione per ottenere il file posizione dell'elemento tela.Ecco un metodo un po' più elegante di alcuni degli altri presenti in questa pagina (IMHO).Puoi passarlo Qualunque 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 il generico findPos funzione dal codice di gestione degli eventi.(Come dovrebbe essere.Dovremmo cercare di limitare le nostre funzioni a un compito ciascuna.)

I valori di offsetLeft E offsetTop sono relativi a offsetParent, che potrebbe essere un wrapper div nodo (o qualsiasi altra cosa, del resto).Quando non è presente alcun elemento che avvolge il file canvas sono relativi a body, quindi non c'è alcun offset da sottrarre.Questo è il motivo per cui dobbiamo determinare la posizione della tela prima di poter fare qualsiasi altra cosa.

Allo stesso modo, e.pageX E e.pageY fornire la posizione del cursore rispetto al documento.Ecco perché sottraiamo l'offset della tela da questi valori per arrivare alla posizione reale.

Un'alternativa per posizionato elements è utilizzare direttamente i valori di e.layerX E e.layerY.Questo è meno affidabile del metodo sopra per due motivi:

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

TreJS 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 quindi a pubblicare.Capito da Qui

Ecco una soluzione semplificata (non funziona con i 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),
    };
}

Stavo creando un'applicazione con a tela su un pdf, che comportava molti ridimensionamenti della tela come ingrandire e rimpicciolire il pdf, e a sua volta ad ogni ingrandimento/riduzione del PDF dovevo ridimensionare la tela per adattare le dimensioni 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 per la versione più recente.

Ecco l'intero frammento di codice che potrebbe essere utile a chiunque lo utilizzi 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 le coordinate del mouse relative alla dimensione della tela, indipendentemente da come si ingrandisce/riduce 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 )
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top