Voglio creare una piccola app di pittura usando la tela. Quindi ho bisogno di trovare la posizione del mouse sulla tela.
Voglio creare una piccola app di pittura usando la tela. Quindi ho bisogno di trovare la posizione del mouse sulla tela.
Risposte:
Per le persone che usano JQuery:
A volte, quando hai elementi nidificati, uno dei quali con l'evento associato, può essere fonte di confusione capire cosa vede il tuo browser come genitore. Qui puoi specificare quale genitore.
Prendi la posizione del mouse e quindi la sottrai dalla posizione di offset dell'elemento genitore.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
Se stai cercando di ottenere la posizione del mouse su una pagina all'interno di un riquadro di scorrimento:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
O la posizione relativa alla pagina:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Nota la seguente ottimizzazione delle prestazioni:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
In questo modo, JQuery non deve cercare #elementogni riga.
Di seguito è disponibile una versione più recente, solo JavaScript, di @anytimecoder per i browser che supportano getBoundingClientRect () .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();avar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Dato che non ho trovato una risposta priva di jQuery che potrei copiare / incollare, ecco la soluzione che ho usato:
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, non e.target. Altrimenti, gli elementi dei bambini lo influenzeranno
Quanto segue calcola la posizione del mouse in relazione all'elemento canvas:
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
In questo esempio, thisfa riferimento exampleall'elemento ed eè l' onmousemoveevento.
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
thisa e.currentTarget, che ti porterà la posizione relativa all'elemento a cui hai aggiunto il listener di eventi.
Non esiste una risposta in javascript puro che restituisce coordinate relative quando l'elemento di riferimento è nidificato all'interno di altri che possono essere con posizionamento assoluto. Ecco una soluzione a questo scenario:
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,
};
}
htmldell'offset degli elementi
while(reference !== undefined)con while(reference). Almeno in Chrome, offsetParent non finisce per essere undefined, ma null. Basta verificare se referenceè vero assicurerà che funzioni con entrambi undefinede null.
offsetParentproprietà, che risulta essere molto utile anche in altre situazioni!
scrollLefte scrollTopcompensare i discendenti scorrevoli.
Un buon resoconto della difficoltà di questo problema può essere trovato qui: http://www.quirksmode.org/js/events_properties.html#position
Utilizzando la tecnica qui descritta è possibile trovare la posizione dei mouse nel documento. Poi basta controllare per vedere se è all'interno del riquadro di delimitazione del vostro elemento, che si possono trovare chiamando element.getBoundingClientRect()che restituirà un oggetto con le seguenti proprietà: { bottom, height, left, right, top, width }. Da lì è banale capire se è successo persino all'interno del tuo elemento.
Ho provato tutte queste soluzioni e grazie alla mia configurazione speciale con un contenitore trasformato a matrice (libreria panzoom) nessuna ha funzionato. Ciò restituisce il valore corretto, anche se ingrandito e spostato:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
Ma solo se non ci sono elementi figlio sulla strada. Questo può essere eluso rendendoli "invisibili" all'evento, usando CSS:
.child {
pointer-events: none;
}
Mi sono imbattuto in questa domanda, ma per farlo funzionare nel mio caso (usando dragover su un elemento DOM (non essere canvas nel mio caso)), ho scoperto che devi solo usare offsetXe offsetYsull'evento dragover-mouse .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
Ho fatto +1 sulla risposta di Mark van Wyk perché mi ha portato nella giusta direzione, ma non mi ha risolto del tutto. Avevo ancora un offset sulla pittura in elementi contenuti in un altro elemento.
Il superficiale mi ha risolto:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
In altre parole, ho semplicemente impilato tutti gli offset da tutti gli elementi nidificati
Nessuna delle risposte sopra è IMO soddisfacente, quindi ecco cosa 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 hai mai bisogno di conoscere l'attuale posizione di scorrimento Y della pagina:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
Per quelli di voi che sviluppano normali siti Web o PWA (Progressive Web App) per dispositivi mobili e / o laptop / monitor con touchscreen, siete arrivati qui perché potreste essere abituati agli eventi del mouse e non conoscete l'esperienza a volte dolorosa di Touch eventi ... yay!
Ci sono solo 3 regole:
mousemoveo touchmoveeventi.mousedowno touchstarteventi.Inutile dire che le cose sono più complicate con gli toucheventi perché possono essercene più di una e sono più flessibili (complicate) degli eventi del mouse. Tratterò solo un singolo tocco qui. Sì, sono pigro, ma è il tipo di tocco più comune, quindi lì.
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.
Preferisci usare Vue.js ? Lo voglio! Quindi il tuo HTML sarebbe simile al seguente:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
puoi farcela
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
Tratto da questo tutorial , con correzioni apportate grazie al commento in alto:
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 )
};
}
Utilizzare su una tela come segue:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
Mi rendo conto di essere un po 'in ritardo, ma funziona con PURE javascript e ti dà persino le coordinate del puntatore all'interno dell'elemento se l'elemento è più grande del viewport e l'utente ha fatto scorrere.
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 ;
}
Come funziona.
La prima cosa che facciamo è ottenere la posizione dell'elemento HTML (l'area del contenuto) rispetto alla finestra corrente. Se la pagina ha barre di scorrimento ed è fatta scorrere, il numero restituito getBoundingClientRect().leftper il tag html sarà negativo. Quindi usiamo questo numero per calcolare la distanza tra l'elemento e la sinistra dell'area del contenuto. Conelement_offset_x = element.getBoundingClientRect().left......;
Conoscere la distanza dell'elemento dall'area del contenuto. event.clientXci dà la distanza del puntatore dal viewport. È importante comprendere che il viewport e l'area del contenuto sono due entità diverse, il viewport può spostarsi se si scorre la pagina. Quindi, clientX restituirà il numero SAME anche se la pagina viene fatta scorrere.
Per compensare ciò, è necessario aggiungere la posizione x del puntatore (relativa alla finestra), alla posizione x della finestra (relativa all'area del contenuto). La posizione X della finestra viene trovata con window.pageXOffset.
Basato sulla soluzione di @ Spider, la mia versione non JQuery è questa:
// 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;
}
Funziona sia con lo scorrimento che con lo zoom (nel qual caso a volte restituisce float).
Le coordinate del mouse all'interno di un'area di disegno possono essere ottenute grazie a event.offsetX e event.offsetY. Ecco un piccolo frammento per dimostrare il mio punto:
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
La HTMLElement.offsetLeftproprietà di sola lettura restituisce il numero di pixel che l'angolo superiore sinistro dell'elemento corrente è spostato a sinistra all'interno diHTMLElement.offsetParent nodo.
Per elementi di blocco, offsetTop,offsetLeft , offsetWidth, e offsetHeightdescrivere il bordo casella di un elemento rispetto al offsetParent.
Tuttavia, per gli elementi a livello di linea (come span) che possono avvolgere da una linea alla successiva offsetTope offsetLeftdescrivere le posizioni della prima casella del bordo (usare Element.getClientRects()per ottenere la sua larghezza e altezza), mentre offsetWidthe offsetHeightdescrivere le dimensioni della casella del bordo delimitante (usare Element.getBoundingClientRect()per ottenere la sua posizione). Pertanto, una casella con sinistra, superiore, larghezza e altezza di offsetLeft,offsetTop , offsetWidtheoffsetHeight non sarà un rettangolo di selezione per un arco con testo avvolto.
HTMLElement.offsetTop
La HTMLElement.offsetTopproprietà di sola lettura restituisce la distanza dell'elemento corrente rispetto alla parte superiore dioffsetParent nodo.
MouseEvent.pageX
Il pageX proprietà di sola lettura restituisce la coordinata X (orizzontale) in pixel dell'evento rispetto all'intero documento. Questa proprietà tiene conto di qualsiasi scorrimento orizzontale della pagina.
MouseEvent.pageY
Il MouseEvent.pageY proprietà di sola lettura restituisce la coordinata Y (verticale) in pixel dell'evento rispetto all'intero documento. Questa proprietà tiene conto di qualsiasi scorrimento verticale della pagina.
Per ulteriori spiegazioni, consultare la rete di sviluppatori Mozilla:
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 offsetsarebbe molto utile per me. Grazie per aver preso in considerazione questa richiesta!
Ho implementato un'altra soluzione che penso sia molto semplice, quindi ho pensato di condividere con voi ragazzi.
Quindi, il problema per me era che il div trascinato saltava a 0,0 per il cursore del mouse. Quindi ho dovuto catturare la posizione dei mouse sul div per regolare la nuova posizione dei div.
Ho letto i div PageX e PageY e ho impostato la parte superiore e sinistra del secondo e quindi per ottenere i valori per regolare le coordinate per mantenere il cursore nella posizione iniziale nel div Uso un listener onDragStart e memorizzo e.nativeEvent .layerX ed e.nativeEvent.layerY che solo nel trigger iniziale ti dà la posizione dei topi all'interno del div trascinabile.
Codice di esempio:
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,
});
}
Spero che questo possa aiutare qualcuno che ha attraversato gli stessi problemi che ho attraversato :)
Devi conoscere la struttura della tua pagina, perché se la tua tela è figlia di un div che a sua volta è figlia di un altro div ... allora la storia diventa più complicata. Ecco il mio codice per una tela che si trova all'interno di 2 livelli di 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);
});
La risposta originale diceva di inserirla in un iframe. La soluzione migliore è utilizzare gli eventi offsetX e offsetY su una tela con il padding impostato su 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>
Puoi usare getBoudingClientRect()il relativegenitore.
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)
})