Je veux faire une petite application de peinture en utilisant la toile. J'ai donc besoin de trouver la position de la souris sur la toile.
Je veux faire une petite application de peinture en utilisant la toile. J'ai donc besoin de trouver la position de la souris sur la toile.
Réponses:
Pour les personnes utilisant JQuery:
Parfois, lorsque vous avez des éléments imbriqués, l'un d'eux avec l'événement attaché, il peut être difficile de comprendre ce que votre navigateur considère comme le parent. Ici, vous pouvez spécifier quel parent.
Vous prenez la position de la souris, puis la soustrayez de la position de décalage de l'élément parent.
var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;
Si vous essayez d'obtenir la position de la souris sur une page dans un volet de défilement:
var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();
Ou la position par rapport à la page:
var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Notez l'optimisation des performances suivante:
var offset = $('#element').offset();
// Then refer to
var x = evt.pageX - offset.left;
De cette façon, JQuery n'a pas à rechercher #elementchaque ligne.
Il existe une nouvelle version uniquement JavaScript ci-dessous par @anytimecoder ci-dessous pour les navigateurs prenant en charge getBoundingClientRect () .
var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();àvar y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
Comme je n'ai pas trouvé de réponse sans jQuery que je pourrais copier / coller, voici la solution que j'ai utilisée:
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, pas e.target. Sinon, les éléments enfants l'affecteront
Ce qui suit calcule la relation de position de la souris avec l'élément canvas:
var example = document.getElementById('example');
example.onmousemove = function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
}
Dans cet exemple, thisfait référence à l' exampleélément et ecorrespond à l' onmousemoveévénement.
var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
thisvers e.currentTarget, cela vous donnera la position relative à l'élément auquel vous avez ajouté l'écouteur d'événements.
Il n'y a pas de réponse en javascript pur qui renvoie des coordonnées relatives lorsque l'élément de référence est imbriqué à l'intérieur d'autres qui peuvent être avec un positionnement absolu. Voici une solution à ce scénario:
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,
};
}
htmldécalage d'élément
while(reference !== undefined)par while(reference). Dans Chrome au moins, le offsetParent ne finit pas par l'être undefined, mais null. Le referencesimple fait de vérifier si la vérité est vraie garantira que cela fonctionne avec les deux undefinedet null.
offsetParentpropriété, qui s'avère très utile dans d'autres situations!
scrollLeftet scrollTopcompenser les descendants défilés.
Une bonne description de la difficulté de ce problème peut être trouvée ici: http://www.quirksmode.org/js/events_properties.html#position
En utilisant la technique qui y est décrite, vous pouvez trouver la position de la souris dans le document. Ensuite , vous vérifiez juste pour voir si elle se trouve dans la zone de délimitation de votre élément, que vous pouvez trouver en appelant element.getBoundingClientRect()qui retournera un objet avec les propriétés suivantes: { bottom, height, left, right, top, width }. À partir de là, il est trivial de savoir si le même événement s'est produit à l'intérieur de votre élément ou non.
J'ai essayé toutes ces solutions et en raison de ma configuration spéciale avec un conteneur transformé en matrice (bibliothèque panzoom), aucune n'a fonctionné. Cela renvoie la valeur correcte, même en cas de zoom et de panoramique:
mouseevent(e) {
const x = e.offsetX,
y = e.offsetY
}
Mais seulement s'il n'y a aucun élément enfant sur le chemin. Cela peut être contourné en les rendant «invisibles» à l'événement, en utilisant CSS:
.child {
pointer-events: none;
}
Je suis tombé sur cette question, mais afin de le faire fonctionner pour mon cas (en utilisant le glisser sur un élément DOM (pas être un canevas dans mon cas)), j'ai trouvé que vous n'avez qu'à utiliser offsetXet offsetYsur l'événement dragover-mouse .
onDragOver(event){
var x = event.offsetX;
var y = event.offsetY;
}
J'ai +1 'La réponse de Mark van Wyk car elle m'a mis dans la bonne direction, mais ne l'a pas tout à fait résolu pour moi. J'avais encore un décalage sur la peinture d'éléments contenus dans un autre élément.
Je l'ai résolu pour moi:
x = e.pageX - this.offsetLeft - $(elem).offset().left;
y = e.pageY - this.offsetTop - $(elem).offset().top;
En d'autres termes - j'ai simplement empilé tous les décalages de tous les éléments imbriqués
Aucune des réponses ci-dessus n'est satisfaisante OMI, alors voici ce que j'utilise:
// 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);
}
Et si jamais vous avez besoin de connaître la position de défilement Y actuelle de la page:
var yscroll = window.pageYOffset
|| (document.documentElement && document.documentElement.scrollTop)
|| document.body.scrollTop; // scroll Y position in page
Pour ceux d'entre vous qui développent des sites Web réguliers ou des PWA (Progressive Web Apps) pour les appareils mobiles et / ou les ordinateurs portables / moniteurs à écrans tactiles, vous avez atterri ici parce que vous pourriez être habitué aux événements de la souris et que vous êtes nouveau dans l'expérience parfois douloureuse de Touch événements ... ouais!
Il n'y a que 3 règles:
mousemoveou lors d' touchmoveévénements.mousedownou lors d' touchstartévénements.Inutile de dire que les touchévénements sont plus compliqués avec les événements car il peut y en avoir plusieurs et ils sont plus flexibles (compliqués) que les événements de souris. Je vais seulement couvrir une seule touche ici. Oui, je suis paresseux, mais c'est le type de contact le plus courant, donc 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.
Vous préférez utiliser Vue.js ? Je fais! Ensuite, votre code HTML ressemblerait à ceci:
<div @mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@touchstart.stop.prevent="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove"
@touchend.stop.prevent="handleTouchEnd">
vous pouvez l'obtenir par
var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
var xCoor = e.clientX;
var yCoor = e.clientY;
}
Tiré de ce tutoriel , avec des corrections apportées grâce au commentaire du haut:
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 )
};
}
Utilisez sur une toile comme suit:
var canvas = document.getElementById( 'myCanvas' );
canvas.addEventListener( 'mousemove', function( evt ) {
var mousePos = getMousePos( canvas, evt );
} );
Je me rends compte que je suis un peu en retard, mais cela fonctionne avec javascript PURE, et il vous donne même les coordonnées du pointeur dans l'élément si l'élément est plus grand que la fenêtre et que l'utilisateur a fait défiler.
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 ;
}
Comment ça fonctionne.
La première chose que nous faisons est d'obtenir l'emplacement de l'élément HTML (la zone de contenu) par rapport à la fenêtre courante. Si la page a des barres de défilement et est défilée, le nombre renvoyé par getBoundingClientRect().leftla balise html sera négatif. Nous utilisons ensuite ce nombre pour calculer la distance entre l'élément et la gauche de la zone de contenu. Avecelement_offset_x = element.getBoundingClientRect().left......;
Connaître la distance de l'élément par rapport à la zone de contenu. event.clientXnous donne la distance entre le pointeur et la fenêtre. Il est important de comprendre que la fenêtre et la zone de contenu sont deux entités différentes, la fenêtre peut se déplacer si la page défile. Par conséquent, clientX renverra le même numéro même si la page défile.
Pour compenser cela, nous devons ajouter la position x du pointeur (par rapport à la fenêtre), à la position x de la fenêtre (par rapport à la zone de contenu). La position X de la fenêtre se trouve avec window.pageXOffset.
Basé sur la solution de @ Spider, ma version non JQuery est la suivante:
// 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;
}
Cela fonctionne à la fois avec le défilement et le zoom (auquel cas, il renvoie parfois des flottants).
Les coordonnées de la souris à l'intérieur d'un canevas peuvent être obtenues grâce à event.offsetX et event.offsetY. Voici un petit extrait pour prouver mon point:
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.offsetLeftpropriété en lecture seule renvoie le nombre de pixels que le coin supérieur gauche de l'élément actuel est décalé vers la gauche dans le HTMLElement.offsetParentnœud.
Pour les éléments de type bloc, offsetTop, offsetLeft, offsetWidth, et offsetHeightdécrire la zone de bordure d'un élément par rapport à la offsetParent.
Cependant, pour les éléments de niveau en ligne (tels que span) qui peuvent passer d'une ligne à la suivante offsetTopet offsetLeftdécrire les positions de la première zone de bordure (à utiliser Element.getClientRects()pour obtenir sa largeur et sa hauteur), tandis que offsetWidthet offsetHeightdécrire les dimensions de la zone de bordure de délimitation (utiliser Element.getBoundingClientRect()pour obtenir sa position). Par conséquent, une boîte à la gauche, haut, largeur et la hauteur offsetLeft, offsetTop, offsetWidthet offsetHeightne sera pas une boîte de délimitation pour une période avec le texte enroulé.
HTMLElement.offsetTop
La HTMLElement.offsetToppropriété en lecture seule renvoie la distance de l'élément actuel par rapport au sommet du offsetParentnœud.
MouseEvent.pageX
La pageXpropriété en lecture seule renvoie la coordonnée X (horizontale) en pixels de l'événement par rapport à l'ensemble du document. Cette propriété prend en compte tout défilement horizontal de la page.
MouseEvent.pageY
La MouseEvent.pageYpropriété en lecture seule renvoie la coordonnée Y (verticale) en pixels de l'événement par rapport à l'ensemble du document. Cette propriété prend en compte tout défilement vertical de la page.
Pour plus d'explications, veuillez consulter le 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
pageet offsetserait très utile pour moi. Merci d'avoir considéré cette demande!
J'ai implémenté une autre solution qui, je pense, est très simple, j'ai donc pensé partager avec vous.
Donc, le problème pour moi était que le div glissé sautait à 0,0 pour le curseur de la souris. J'ai donc dû capturer la position de la souris sur le div pour ajuster la nouvelle position du div.
J'ai lu les divs PageX et PageY et défini le haut et la gauche du en fonction de cela, puis pour obtenir les valeurs pour ajuster les coordonnées pour garder le curseur dans la position initiale dans le div, j'utilise un écouteur onDragStart et stocke le e.nativeEvent .layerX et e.nativeEvent.layerY qui seulement dans le déclencheur initial vous donne la position de la souris dans la div glissable.
Exemple de code:
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,
});
}
J'espère que cela aidera quelqu'un qui a connu les mêmes problèmes que moi. :)
Vous devez connaître la structure de votre page, car si votre toile est un enfant d'un div qui est à son tour un enfant d'un autre div ... alors l'histoire devient plus compliquée. Voici mon code pour une toile qui est à l'intérieur de 2 niveaux 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);
});
La réponse originale a dit de le mettre dans un iframe. La meilleure solution consiste à utiliser les événements offsetX et offsetY sur un canevas dont le remplissage est défini sur 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>
Vous pouvez utiliser getBoudingClientRect()le relativeparent.
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)
})