Como obtenho as coordenadas de um clique do mouse em um elemento da tela?

276

Qual é a maneira mais simples de adicionar um manipulador de eventos click a um elemento da tela que retornará as coordenadas xey do clique (em relação ao elemento da tela)?

Nenhuma compatibilidade de navegador herdada é necessária, o Safari, o Opera e o Firefox farão.

Tom
fonte
Isso não deve ser diferente de obter eventos do mouse a partir de elementos dom normais. O quirksmode tem uma boa referência nisso.
Airportyh 11/11/09
4
O código listado acima funciona apenas quando a tela não está no fundo de outros contêineres. Em geral, você precisa usar algo como a função offset de jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] para obter o deslocamento correto de maneira cruzada no navegador. Isso é uma verdadeira dor de cabeça.
Aaron Watters
O código postado acima com o Update não funcionará se a página que contém a tela rola.
Timothy Kim
Eu removi minha "resposta" antiga que foi incluída como uma atualização para a pergunta. Como mencionado, estava desatualizado e incompleto.
Tom
3
Como existem 50 respostas aqui, recomendo rolar para a seguinte resposta: patriques - um bom e simples forro de 5 linhas.
Igor L.

Respostas:

77

Edit 2018: Esta resposta é bastante antiga e usa verificações para navegadores antigos que não são mais necessários, pois as propriedades clientXe clientYfuncionam em todos os navegadores atuais. Convém consultar o Patriques Answer para obter uma solução mais simples e mais recente.

Resposta original:
Conforme descrito em um artigo que encontrei na época, mas não existe mais:

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;

Funcionou perfeitamente bem para mim.

N4ppeL
fonte
30
Essa solução nem sempre funciona - a resposta de Ryan Artecona funciona no caso mais geral, quando a tela não está necessariamente posicionada em relação à página inteira.
Chris Johnson
3
Esta solução não é adequada se o desempenho importa, pois o acesso ao Dom é feito a cada clique / movimento. E o getBoundingClientRect existe agora e é mais elegante.
GameAlchemist
192

Se você gosta de simplicidade, mas ainda deseja funcionalidade entre navegadores, achei que essa solução funcionou melhor para mim. Esta é uma simplificação da solução da @ Aldekein, mas sem o 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
fonte
Se a página estiver rolada para baixo, acho que também se deve considerar o deslocamento da rolagem do documento.
Peppe LG
8
O retângulo do cliente delimitador @ PeppeL-G calcula isso para você. Você pode testá-lo facilmente no console antes de postar um comentário (foi o que eu fiz).
Tomáš Zato - Restabelecer Monica 29/11
1
@ TomášZato, oh, getBoundingClientRectretorna posições em relação à porta de visualização? Então meu palpite estava errado. Eu nunca o testei, pois isso nunca foi um problema para mim e, por gentileza, quis avisar outros leitores sobre um potencial problema que vi, mas obrigado por seu esclarecimento.
Peppe LG
1
Isso não funciona se a tela for dimensionada. Não tenho certeza se isso é um bug do navegador.
Jeroen
2
Adicione uso para alguém como eu:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion 22/06
179

Atualização (5/5/16): a resposta de patriques deve ser usada, pois é mais simples e mais confiável.


Como a tela nem sempre é estilizada em relação à página inteira, canvas.offsetLeft/Topela nem sempre retorna o que você precisa. Ele retornará o número de pixels compensados ​​em relação ao elemento offsetParent, que pode ser algo como um divelemento que contém a tela com um position: relativeestilo aplicado. Para explicar isso, você precisa percorrer a cadeia de offsetParents, começando com o próprio elemento da tela. Este código funciona perfeitamente para mim, testado no Firefox e Safari, mas deve funcionar para todos.

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;

A última linha facilita as coisas para obter as coordenadas do mouse em relação a um elemento da tela. Tudo o que é necessário para obter as coordenadas úteis é

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Ryan Artecona
fonte
8
Não, ele está usando o objeto de protótipo javascript embutido --- developer.mozilla.org/en/…
garg
14
meu Chrome tem event.offsetXe event.offsetYatributos, então modifiquei sua solução adicionando if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. parece que funciona.
Baczek 28/05
3
Baczek está correto sobre o Chrome event.offsetXe event.offsetYtambém funciona no IE9. Para o Firefox (testado com v13), você pode usar event.layerXe event.layerY.
precisa saber é
3
Eu também adicionei isso: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc
4
Esta versão final da resposta não funcionou para mim. No Firefox, se a tela inteira estiver rolada, obtive o valor deslocado como saída. O que funcionou para mim foi uma solução muito semelhante, dada em stackoverflow.com/a/10816667/578749 que, em vez de event.pageX / Y, subtraiu o deslocamento calculado de event.clientX / Y. Alguém poderia revisar isso e explicar?
Lvella
33

O navegador moderno agora lida com isso para você. Chrome, IE9 e Firefox suportam o offsetX / Y assim, passando o evento pelo manipulador de cliques.

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

A maioria dos navegadores modernos também suporta layerX / Y, no entanto, Chrome e IE usam layerX / Y para o deslocamento absoluto do clique na página, incluindo margem, preenchimento, etc. No Firefox, layerX / Y e offsetX / Y são equivalentes, mas o deslocamento não existe anteriormente. Portanto, para compatibilidade com navegadores um pouco mais antigos, você pode usar:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
mafafu
fonte
1
interessante como layerX, layerY é definido no Chrome e no Firefox, mas no Chrome é impreciso (ou significa outra coisa).
Julian Mann
@JulianMann Obrigado pela informação. Atualizei esta resposta com base no suporte mais atual. Parece que você pode se safar do offsetX / Y quase universalmente agora.
Mafafu 06/07/19
18

De acordo com o novo Quirksmode, os métodos clientXe clientYsão suportados em todos os principais navegadores. Então, aqui vai - o código bom e funcional que funciona em uma div de rolagem em uma página com barras de rolagem:

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

Isso também requer jQuery para $(canvas).offset().

Aldekein
fonte
Equivalente à resposta @ N4ppeL.
Paweł Szczur
13

Fiz uma demonstração completa que funciona em todos os navegadores com o código fonte completo da solução deste problema: Coordenadas de um mouse, clique em Canvas em Javascript . Para experimentar a demonstração, copie o código e cole-o em um editor de texto. Em seguida, salve-o como example.html e, finalmente, abra o arquivo com um navegador.

Manuel Ignacio López Quintero
fonte
11

Aqui está uma pequena modificação na resposta de Ryan Artecona para telas com uma largura variável (%):

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

Seja cauteloso ao fazer a conversão de coordenadas; existem vários valores não relacionados ao navegador retornados em um evento de clique. Usar o clientX e o clientY por si só não será suficiente se a janela do navegador for rolada (verificada no Firefox 3.5 e Chrome 3.0).

Este artigo do modo quirks fornece uma função mais correta que pode usar pageX ou pageY ou uma combinação de clientX com document.body.scrollLeft e clientY com document.body.scrollTop para calcular a coordenada do clique em relação à origem do documento.

UPDATE: Além disso, offsetLeft e offsetTop são relativos ao tamanho acolchoado do elemento, não ao tamanho interior. Uma tela com o estilo padding: aplicado não reportará a parte superior esquerda de sua região de conteúdo como offsetLeft. Existem várias soluções para esse problema; o mais simples pode ser limpar todos os estilos de borda, preenchimento etc. na própria tela e aplicá-los a uma caixa que contém a tela.

fixermark
fonte
7

Não sei ao certo qual é o objetivo de todas essas respostas que passam pelos elementos dos pais e fazem todo tipo de coisa estranha .

O HTMLElement.getBoundingClientRectmétodo foi desenvolvido para lidar com a posição real da tela de qualquer elemento. Isso inclui rolagem; portanto, coisas do tipo scrollTopnão são necessárias:

(do MDN) A quantidade de rolagem realizada na área da janela de exibição (ou qualquer outro elemento rolável ) é levada em consideração ao calcular o retângulo delimitador

Imagem normal

A abordagem mais simples já foi publicada aqui. Isso está correto desde que nenhuma regra CSS selvagem esteja envolvida.

Manuseio de lona esticada / imagem

Quando a largura do pixel da imagem não corresponder à largura do CSS, será necessário aplicar uma proporção nos valores do 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];
}

Contanto que a tela não tenha borda, ela funciona para imagens esticadas (jsFiddle) .

Manipulação de bordas CSS

Se a tela tem uma borda grossa, as coisas ficam um pouco complicadas . Você literalmente precisará subtrair a borda do retângulo delimitador. Isso pode ser feito usando .getComputedStyle . Esta resposta descreve o processo .

A função cresce um pouco:

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

Não consigo pensar em nada que confunda essa função final. Veja você mesmo no JsFiddle .

Notas

Se você não gosta de modificar os prototypes nativos , basta alterar a função e chamá-la por (canvas, event)(e substituir qualquer thispor canvas).

Tomáš Zato - Restabelecer Monica
fonte
6

Aqui está um tutorial muito bom

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

espero que isto ajude!

FraZer
fonte
A solução de Ryan Artecona não funcionou para navegadores tablet com zoom. No entanto, este fez.
Andy Meyers
Não funciona com imagens com CSS width/ heightsubstituído, mas ainda uma das melhores soluções.
Tomáš Zato - Restabelece Monica
3

Usando jQuery em 2016, para obter coordenadas de clique em relação à tela, eu faço:

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

Isso funciona, pois o offset da tela () e o jqEvent.pageX / Y são relativos ao documento, independentemente da posição de rolagem.

Observe que, se sua tela for dimensionada, essas coordenadas não serão as mesmas que as coordenadas lógicas da tela . Para obtê-los, você também faria:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}
Salsaparrilha
fonte
Uau. Como o 'jqEvent' é definido? Ou 'lona'? Ou no segundo exemplo 'coords'? Você precisa executar o primeiro exemplo antes do segundo? Nesse caso, por que você não escreveria "para obtê-los, você também faria"? Tudo isso funciona em uma função onclick ou o quê? Conte um pouco de contexto, companheiro. E, considerando que a pergunta original foi feita em 2008, acho que você precisa responder no contexto da tecnologia disponível em 2008. Refine sua resposta usando jQuery válido da versão que estava disponível na época (v1.2). ;)
Ayelis
1
OK, desculpe pela minha presunção. Vou editar para remover o que. Pretendia fornecer a resposta usando as estruturas mais recentes. E acredito que um programador não precisaria ser explicado sobre o que são jqEvent, canvas e coords.
Salsaparrilha 21/04
Parece bom. Obrigado pela sua contribuição! Desculpe, eu te dei um tempo difícil! ;)
Ayelis
3

Portanto, este é um tópico simples, mas um pouco mais complicado do que parece.

Primeiro, geralmente existem questões conflitantes aqui

  1. Como obter coordenadas relativas do elemento do mouse

  2. Como obter coordenadas de mouse de pixel de tela para a API de tela 2D ou WebGL

então, respostas

Como obter coordenadas relativas do elemento do mouse

Se o elemento é ou não uma tela que obtém as coordenadas relativas do mouse é o mesmo para todos os elementos.

Existem 2 respostas simples para a pergunta "Como obter coordenadas relativas do mouse na tela"

Resposta simples nº 1: uso offsetXeoffsetY

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

Esta resposta funciona no Chrome, Firefox e Safari. Ao contrário de todos os outros valores de eventos offsetXe offsetYtransforma take CSS em conta.

O maior problema offsetXe, a offsetYpartir de 2019/05, eles não existem em eventos de toque e, portanto, não podem ser usados ​​com o iOS Safari. Eles existem nos Eventos de ponteiro que existem no Chrome e Firefox, mas não no Safari, embora aparentemente o Safari esteja trabalhando nele .

Outra questão é que os eventos devem estar na própria tela. Se você colocá-los em algum outro elemento ou na janela, não será possível escolher a tela posteriormente como seu ponto de referência.

Resposta simples nº 2 clientX, uso clientYecanvas.getBoundingClientRect

Se você não se importa com as transformações CSS, a próxima resposta mais simples é chamar canvas. getBoundingClientRect()e subtrair a esquerda de clientXe topde clientYcomo em

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

Isso funcionará desde que não haja transformações CSS. Também funciona com eventos de toque e, portanto, com o 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;
});

Como obter coordenadas de mouse de pixel de tela para a API de tela 2D

Para isso, precisamos pegar os valores que obtivemos acima e converter do tamanho em que a tela é exibida para o número de pixels na própria tela

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

ou com 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: Em todos os casos, não adicione preenchimento ou bordas à tela. Fazer isso complicará bastante o código. Em vez de desejar uma borda ou preenchimento, coloque a tela em outro elemento e adicione o preenchimento e / ou borda ao elemento externo.

Exemplo de trabalho usando event.offsetX,event.offsetY

Exemplo de trabalho usando canvas.getBoundingClientRecte event.clientXeevent.clientY

gman
fonte
2

Eu recomendo este 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>

fonte
para que serve x = new Number()? O código abaixo que reatribui, o xque significa que o Número alocado é imediatamente descartado
gman
1

Você poderia apenas fazer:

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

Isso fornecerá a posição exata do ponteiro do mouse.

user2310569
fonte
1

Veja a demonstração em 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
fonte
0

Aqui estão algumas modificações da solução de Ryan Artecona acima.

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 Hi
fonte
0

Primeiro, como já foi dito, você precisa de uma função para obter a posição do elemento da tela . Aqui está um método um pouco mais elegante do que alguns dos outros desta página (IMHO). Você pode passar qualquer elemento e obter sua posição no 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;
}

Agora calcule a posição atual do cursor em relação a isso:

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

Observe que eu separei a findPosfunção genérica do código de manipulação de eventos. ( Como deveria ser . Devemos tentar manter nossas funções em uma tarefa cada.)

Os valores de offsetLefte offsetTopsão relativos a offsetParent, que podem ser algum divnó do wrapper (ou qualquer outra coisa, nesse caso). Quando não há um elemento agrupando, canvaseles são relativos ao body, portanto, não há deslocamento para subtrair. É por isso que precisamos determinar a posição da tela antes que possamos fazer qualquer outra coisa.

Similary e.pageXe e.pageYforneça a posição do cursor em relação ao documento. É por isso que subtraímos o deslocamento da tela desses valores para chegar à posição verdadeira.

Uma alternativa para elementos posicionados é usar diretamente os valores de e.layerXe e.layerY. Isso é menos confiável que o método acima por dois motivos:

  1. Esses valores também são relativos ao documento inteiro quando o evento não ocorre dentro de um elemento posicionado
  2. Eles não fazem parte de nenhum padrão
Wayne
fonte
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;

Depois de tentar muitas soluções. Isso funcionou para mim. Pode ajudar alguém, portanto, postando. Entendi daqui

Aniket Betkikar
fonte
0

Aqui está uma solução simplificada (isso não funciona com bordas / rolagem):

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
fonte
0

Eu estava criando um aplicativo com uma tela sobre um pdf, que envolvia muitos redimensionamentos de tela, como Aumentar e diminuir o zoom do pdf e, por sua vez, a cada aumento / redução do PDF que eu tinha que redimensionar a tela para adaptar o No tamanho do pdf, passei por muitas respostas no stackOverflow e não encontrei uma solução perfeita que acabaria resolvendo o problema.

Eu estava usando rxjs e angular 6 e não encontrei nenhuma resposta específica para a versão mais recente.

Aqui está o trecho de código inteiro que seria útil para qualquer pessoa que utilize o rxjs para desenhar sobre a 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);
      });
  }

E aqui está o trecho que corrige, as coordenadas do mouse em relação ao tamanho da tela, independentemente de como você aumenta ou diminui o zoom na 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 )
};
Divyanshu Rawat
fonte
-1

Ei, isso está no dojo, apenas porque é o que eu já tinha o código para um projeto.

Deve ser bastante óbvio como convertê-lo novamente em JavaScript sem dojo vanilla.

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

Espero que ajude.

Brian Gianforcaro
fonte
6
clientX / clientY não se comporta de maneira semelhante nos navegadores.
tfwright