Quero fazer um pequeno aplicativo de pintura usando tela. Então, preciso encontrar a posição do mouse na tela.
Quero fazer um pequeno aplicativo de pintura usando tela. Então, preciso encontrar a posição do mouse na tela.
Respostas:
Para pessoas que usam JQuery:
Às vezes, quando você aninha elementos, um deles com o evento associado, pode ser confuso entender o que o navegador vê como pai. Aqui, você pode especificar qual pai.
Você toma a posição do mouse e subtrai-a da posição de deslocamento do elemento pai.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
Se você estiver tentando obter a posição do mouse em uma página dentro de um painel de rolagem:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
Ou a posição relativa à página:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Observe a seguinte otimização de desempenho:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
Dessa maneira, o JQuery não precisa procurar #elementpor cada linha.
Há uma versão mais recente, somente para JavaScript, abaixo, de @anytimecoder abaixo, para navegadores que suportam getBoundingClientRect () .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();avar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Como não encontrei uma resposta sem jQuery que pudesse copiar / colar, eis a solução que usei:
function clickEvent(e) {
// e = Mouse click event.
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left; //x position within the element.
var y = e.clientY - rect.top; //y position within the element.
}
e.currentTarget, não o e.target. Caso contrário, os elementos filhos vão afetá-lo
A seguir, calcula a relação da posição do mouse com o elemento da tela:
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
Neste exemplo, thisrefere-se ao exampleelemento e eé o onmousemoveevento
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
thispara e.currentTarget, que fornecerá a posição em relação ao elemento ao qual você adicionou o ouvinte de evento.
Não há resposta em javascript puro que retorne coordenadas relativas quando o elemento de referência estiver aninhado dentro de outros que possam estar com posicionamento absoluto. Aqui está uma solução para este cenário:
function getRelativeCoordinates (event, referenceElement) {
const position = {
x: event.pageX,
y: event.pageY
};
const offset = {
left: referenceElement.offsetLeft,
top: referenceElement.offsetTop
};
let reference = referenceElement.offsetParent;
while(reference){
offset.left += reference.offsetLeft;
offset.top += reference.offsetTop;
reference = reference.offsetParent;
}
return {
x: position.x - offset.left,
y: position.y - offset.top,
};
}
htmlelemento de compensação
while(reference !== undefined)por while(reference). No Chrome, pelo menos, o offsetParent não acaba sendo undefined, mas null. Apenas verificar se referenceé verdade garantirá que funcione com ambos undefinede null.
offsetParentpropriedade, o que acaba sendo muito útil também em outras situações!
scrollLefte scrollTopcompensar descendentes rolados.
Uma boa descrição da dificuldade desse problema pode ser encontrada aqui: http://www.quirksmode.org/js/events_properties.html#position
Usando a técnica descrita lá, você pode encontrar a posição do mouse no documento. Então você acabou de verificar para ver se ele está dentro da caixa delimitadora do seu elemento, onde pode encontrar chamando element.getBoundingClientRect()que irá retornar um objeto com as seguintes propriedades: { bottom, height, left, right, top, width }. A partir daí, é trivial descobrir se o mesmo aconteceu dentro do seu elemento ou não.
Tentei todas essas soluções e, devido à minha configuração especial com um contêiner transformado em matriz (biblioteca panzoom), nenhum funcionou. Isso retorna o valor correto, mesmo se ampliado e panorâmico:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
Mas somente se não houver elementos filhos no caminho. Isso pode ser contornado, tornando-os 'invisíveis' para o evento, usando CSS:
.child {
pointer-events: none;
}
Me deparei com essa pergunta, mas, para fazê-lo funcionar no meu caso (usando dragover em um elemento DOM (não sendo canvas no meu caso)), descobri que você só precisa usar offsetXe offsetYno evento dragover-mouse .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
Marquei a resposta de Mark van Wyk com +1, pois ela me levou na direção certa, mas não a resolveu completamente para mim. Eu ainda tinha um deslocamento na pintura de elementos contidos em outro elemento.
A seguir resolvi isso para mim:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
Em outras palavras - eu simplesmente empilhei todas as compensações de todos os elementos aninhados
Nenhuma das respostas acima é satisfatória IMO, então aqui está o que eu uso:
// Cross-browser AddEventListener
function ael(e, n, h){
if( e.addEventListener ){
e.addEventListener(n, h, true);
}else{
e.attachEvent('on'+n, h);
}
}
var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW
if(touch){
ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}
// local mouse X,Y position in element
function showLocalPos(e){
document.title = (mx - e.getBoundingClientRect().left)
+ 'x'
+ Math.round(my - e.getBoundingClientRect().top);
}
E se você precisar conhecer a atual posição de rolagem Y da página:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
Para aqueles que desenvolvem sites regulares ou PWAs (Progressive Web Apps) para dispositivos móveis e / ou laptops / monitores com telas sensíveis ao toque, você chegou aqui porque pode estar acostumado a eventos de mouse e é novo na experiência às vezes dolorosa do Touch eventos ... yay!
Existem apenas três regras:
mousemoveou touchmoveeventos.mousedownou touchstarteventos.Escusado será dizer que as coisas são mais complicadas com os toucheventos porque podem haver mais de um e são mais flexíveis (complicadas) que os eventos do mouse. Eu só vou cobrir um único toque aqui. Sim, estou sendo preguiçoso, mas é o tipo de toque mais comum, então existe.
var posTop;
var posLeft;
function handleMouseDown(evt) {
var e = evt || window.event; // Because Firefox, etc.
posTop = e.target.offsetTop;
posLeft = e.target.offsetLeft;
e.target.style.background = "red";
// The statement above would be better handled by CSS
// but it's just an example of a generic visible indicator.
}
function handleMouseMove(evt) {
var e = evt || window.event;
var x = e.offsetX; // Wonderfully
var y = e.offsetY; // Simple!
e.target.innerHTML = "Mouse: " + x + ", " + y;
if (posTop)
e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop);
}
function handleMouseOut(evt) {
var e = evt || window.event;
e.target.innerHTML = "";
}
function handleMouseUp(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
}
function handleTouchStart(evt) {
var e = evt || window.event;
var rect = e.target.getBoundingClientRect();
posTop = rect.top;
posLeft = rect.left;
e.target.style.background = "green";
e.preventDefault(); // Unnecessary if using Vue.js
e.stopPropagation(); // Same deal here
}
function handleTouchMove(evt) {
var e = evt || window.event;
var pageX = e.touches[0].clientX; // Touches are page-relative
var pageY = e.touches[0].clientY; // not target-relative
var x = pageX - posLeft;
var y = pageY - posTop;
e.target.innerHTML = "Touch: " + x + ", " + y;
e.target.innerHTML += "<br>" + pageX + ", " + pageY;
e.preventDefault();
e.stopPropagation();
}
function handleTouchEnd(evt) {
var e = evt || window.event;
e.target.style.background = "yellow";
// Yes, I'm being lazy and doing the same as mouseout here
// but obviously you could do something different if needed.
e.preventDefault();
e.stopPropagation();
}
div {
background: yellow;
height: 100px;
left: 50px;
position: absolute;
top: 80px;
user-select: none; /* Disable text selection */
-ms-user-select: none;
width: 100px;
}
<div
onmousedown="handleMouseDown()"
onmousemove="handleMouseMove()"
onmouseout="handleMouseOut()"
onmouseup="handleMouseUp()"
ontouchstart="handleTouchStart()"
ontouchmove="handleTouchMove()"
ontouchend="handleTouchEnd()">
</div>
Move over box for coordinates relative to top left of box.<br>
Hold mouse down or touch to change color.<br>
Drag to turn on coordinates relative to top left of page.
Prefere usar o Vue.js ? Eu faço! Então seu HTML ficaria assim:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
você pode obtê-lo
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
Retirado deste tutorial , com correções feitas graças ao comentário principal:
function getMousePos( canvas, evt ) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.floor( ( evt.clientX - rect.left ) / ( rect.right - rect.left ) * canvas.width ),
y: Math.floor( ( evt.clientY - rect.top ) / ( rect.bottom - rect.top ) * canvas.height )
};
}
Use em uma tela da seguinte maneira:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
Percebo que estou um pouco atrasado, mas isso funciona com javascript PURE e ainda fornece as coordenadas do ponteiro dentro do elemento se o elemento for maior que a viewport e o usuário tiver rolado.
var element_offset_x ; // The distance from the left side of the element to the left of the content area
....// some code here (function declaration or element lookup )
element_offset_x = element.getBoundingClientRect().left - document.getElementsByTagName("html")[0].getBoundingClientRect().left ;
....// code here
function mouseMoveEvent(event)
{
var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ;
}
Como funciona.
A primeira coisa que fazemos é obter a localização do elemento HTML (a área de conteúdo) em relação à viewport atual. Se a página tiver barras de rolagem e estiver rolada, o número retornado pela getBoundingClientRect().lefttag html será negativo. Em seguida, usamos esse número para calcular a distância entre o elemento e a esquerda da área de conteúdo. Comelement_offset_x = element.getBoundingClientRect().left......;
Conhecendo a distância do elemento da área de conteúdo. event.clientXnos dá a distância do ponteiro da janela de visualização. É importante entender que a viewport e a área de conteúdo são duas entidades diferentes; a viewport pode se mover se a página for rolada. Portanto, o clientX retornará o mesmo número, mesmo que a página seja rolada.
Para compensar isso, precisamos adicionar a posição x do ponteiro (em relação à viewport), à posição x da viewport (em relação à área de conteúdo). A posição X da viewport é encontrada com window.pageXOffset.
Com base na solução do @ Spider, minha versão não JQuery é a seguinte:
// Get the container element's bounding box
var sides = document.getElementById("container").getBoundingClientRect();
// Apply the mouse event listener
document.getElementById("canvas").onmousemove = (e) => {
// Here 'self' is simply the current window's context
var x = (e.clientX - sides.left) + self.pageXOffset;
var y = (e.clientY - sides.top) + self.pageYOffset;
}
Isso funciona tanto com rolagem quanto com zoom (nesse caso, às vezes, ele retorna flutuantes).
As coordenadas do mouse dentro de uma tela podem ser obtidas graças a event.offsetX e event.offsetY. Aqui está um pequeno trecho para provar meu argumento:
c=document.getElementById("c");
ctx=c.getContext("2d");
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
c.addEventListener("mousemove",function(mouseEvt){
// the mouse's coordinates on the canvas are just below
x=mouseEvt.offsetX;
y=mouseEvt.offsetY;
// the following lines draw a red square around the mouse to prove it
ctx.fillStyle="black";
ctx.fillRect(0,0,100,100);
ctx.fillStyle="red";
ctx.fillRect(x-5,y-5,10,10);
});
body {
background-color: blue;
}
canvas {
position: absolute;
top: 50px;
left: 100px;
}
<canvas id="c" width="100" height="100"></canvas>
canvas.onmousedown = function(e) {
pos_left = e.pageX - e.currentTarget.offsetLeft;
pos_top = e.pageY - e.currentTarget.offsetTop;
console.log(pos_left, pos_top)
}
HTMLElement.offsetLeft
A HTMLElement.offsetLeftpropriedade somente leitura retorna o número de pixels que o canto superior esquerdo do elemento atual é deslocado para a esquerda dentro doHTMLElement.offsetParent nó.
Para elementos de bloco, offsetTop, offsetLeft, offsetWidth, e offsetHeightdescrevem a caixa fronteira de um elemento em relação ao offsetParent.
No entanto, para os elementos de nível em linha (tal como span) que pode envolver a partir de uma linha para a seguinte, offsetTope offsetLeftdescrevem as posições da primeira caixa da fronteira (uso Element.getClientRects()para obter a sua largura e altura), enquanto offsetWidthe offsetHeightdescrever as dimensões da caixa de fronteira delimitadora (use Element.getBoundingClientRect()para obter sua posição). Portanto, uma caixa com a esquerda, superior, largura e altura de offsetLeft, offsetTop, offsetWidthe offsetHeightnão será uma caixa delimitadora para um período com o texto envolvido.
HTMLElement.offsetTop
A HTMLElement.offsetToppropriedade somente leitura retorna a distância do elemento atual em relação à parte superior do offsetParentnó.
MouseEvent.pageX
A pageXpropriedade somente leitura retorna a coordenada X (horizontal) em pixels do evento em relação ao documento inteiro. Essa propriedade leva em consideração qualquer rolagem horizontal da página.
MouseEvent.pageY
A MouseEvent.pageYpropriedade somente leitura retorna a coordenada Y (vertical) em pixels do evento em relação ao documento inteiro. Essa propriedade leva em consideração qualquer rolagem vertical da página.
Para mais explicações, consulte a Mozilla Developer Network:
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https: // developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop
pagee offsetseria muito útil para mim. Obrigado por considerar esta solicitação!
Eu implementei uma outra solução que eu acho muito simples, então pensei em compartilhar com vocês.
Portanto, o problema para mim era que a div arrastada saltaria para 0,0 para o cursor do mouse. Então, eu precisava capturar a posição do mouse no div para ajustar a nova posição do div.
Eu li as divs PageX e PageY e defino a parte superior e esquerda de acordo com isso e, em seguida, para obter os valores para ajustar as coordenadas para manter o cursor na posição inicial na div, uso um ouvinte onDragStart e armazeno o e.nativeEvent .layerX e e.nativeEvent.layerY que somente no acionador inicial fornecem a posição do mouse na div arrastável.
Código de exemplo:
onDrag={(e) => {
let newCoords;
newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
this.props.onDrag(newCoords, e, item.id);
}}
onDragStart={
(e) => {
this.setState({
correctionX: e.nativeEvent.layerX,
correctionY: e.nativeEvent.layerY,
});
}
Espero que isso ajude alguém que passou pelos mesmos problemas pelos quais passei :)
Você precisa conhecer a estrutura da sua página, porque se sua tela é filha de uma div que, por sua vez, é filha de outra div ... então a história fica mais complicada. Aqui está o meu código para uma tela que está dentro de 2 níveis de div s:
canvas.addEventListener("click", function(event) {
var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft);
var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop);
console.log("relative x=" + x, "relative y" + y);
});
A resposta original disse para colocá-lo em um iframe. A melhor solução é usar os eventos offsetX e offsetY em uma tela com o preenchimento definido como 0px.
<html>
<body>
<script>
var main=document.createElement('canvas');
main.width="200";
main.height="300";
main.style="padding:0px;margin:30px;border:thick dashed red";
document.body.appendChild(main);
// adding event listener
main.addEventListener('mousemove',function(e){
var ctx=e.target.getContext('2d');
var c=Math.floor(Math.random()*0xFFFFFF);
c=c.toString(16); for(;c.length<6;) c='0'+c;
ctx.strokeStyle='#'+c;
ctx.beginPath();
ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI);
ctx.stroke();
e.target.title=e.offsetX+' '+e.offsetY;
});
// it worked! move mouse over window
</script>
</body>
</html>
Você pode usar getBoudingClientRect()o relativepai.
document.addEventListener("mousemove", (e) => {
let xCoord = e.clientX - e.target.getBoundingClientRect().left + e.offsetX
let yCoord = e.clientY - e.target.getBoundingClientRect().top + e.offsetY
console.log("xCoord", xCoord, "yCoord", yCoord)
})