Je veux détecter où a MouseEvent
a eu lieu, en coordonnées relatives à l'élément cliqué . Pourquoi ? Parce que je veux ajouter un élément enfant positionné de manière absolue à l'emplacement cliqué.
Je sais comment le détecter lorsqu'il n'existe aucune transformation CSS3 (voir la description ci-dessous). Cependant, lorsque j'ajoute une transformation CSS3, mon algorithme se casse la figure et je ne sais pas comment le réparer.
Je n'utilise aucune bibliothèque JavaScript, et je veux comprendre comment les choses fonctionnent en JavaScript pur. Alors, s'il vous plaît, ne répondez pas par "utilisez simplement jQuery".
Au fait, je veux une solution qui fonctionne pour tous les MouseEvents, pas seulement pour le "click". Cela n'a pas d'importance, car je pense que tous les événements souris partagent les mêmes propriétés, donc la même solution devrait fonctionner pour tous.
Informations générales
Selon Spécification DOM niveau 2 , a MouseEvent
possède quelques propriétés liées à l'obtention des coordonnées de l'événement :
-
screenX
etscreenY
retourne les coordonnées de l'écran (l'origine est le coin supérieur gauche de l'écran de l'utilisateur) -
clientX
etclientY
retourne les coordonnées relatives à la fenêtre du document.
Ainsi, afin de trouver la position de la MouseEvent
par rapport au contenu de l'élément cliqué, je dois faire ce calcul :
ev.clientX - this.getBoundingClientRect().left - this.clientLeft + this.scrollLeft
-
ev.clientX
est la coordonnée relative à la fenêtre du document -
this.getBoundingClientRect().left
est la position de l'élément par rapport à la fenêtre du document. -
this.clientLeft
est la quantité de bordure (et de barre de défilement) entre la limite de l'élément et les coordonnées intérieures. -
this.scrollLeft
est la quantité de défilement à l'intérieur de l'élément
getBoundingClientRect()
, clientLeft
et scrollLeft
sont spécifiés à Module de visualisation du CSSOM .
Expérimenter sans CSS Transform (ça marche)
Confus ? Essayez le morceau suivant de JavaScript et HTML . En cliquant, un point rouge devrait apparaître à l'endroit exact où le clic s'est produit. Cette version est "assez simple" et fonctionne comme prévu.
function click_handler(ev) {
var rect = this.getBoundingClientRect();
var left = ev.clientX - rect.left - this.clientLeft + this.scrollLeft;
var top = ev.clientY - rect.top - this.clientTop + this.scrollTop;
var dot = document.createElement('div');
dot.setAttribute('style', 'position:absolute; width: 2px; height: 2px; top: '+top+'px; left: '+left+'px; background: red;');
this.appendChild(dot);
}
document.getElementById("experiment").addEventListener('click', click_handler, false);
<div id="experiment" style="border: 5px inset #AAA; background: #CCC; height: 400px; position: relative; overflow: auto;">
<div style="width: 900px; height: 2px;"></div>
<div style="height: 900px; width: 2px;"></div>
</div>
Expérimenter l'ajout d'une transformation CSS (cela échoue)
Maintenant, essayez d'ajouter un CSS transform
:
#experiment {
transform: scale(0.5);
-moz-transform: scale(0.5);
-o-transform: scale(0.5);
-webkit-transform: scale(0.5);
/* Note that this is a very simple transformation. */
/* Remember to also think about more complex ones, as described below. */
}
L'algorithme ne connaît pas les transformations, et calcule donc une position erronée. De plus, les résultats sont différents entre Firefox 3.6 et Chrome 12. Opera 11.50 se comporte exactement comme Chrome.
Dans cet exemple, la seule transformation était la mise à l'échelle, je pouvais donc multiplier le facteur d'échelle pour calculer la bonne coordonnée. Cependant, si nous pensons aux transformations arbitraires (mise à l'échelle, rotation, inclinaison, translation, matrice), et même aux transformations imbriquées (un élément transformé à l'intérieur d'un autre élément transformé), alors nous avons vraiment besoin d'un meilleur moyen de calculer les coordonnées.
7 votes
S'il vous plaît, ne répondez pas par "utilisez simplement jQuery" - je vous donnerais une note supérieure rien que pour ça...
0 votes
Il me semble que si vous aviez un moyen d'obtenir la matrice de transformation 3D qui décrit la transformation originale, vous seriez en mesure d'obtenir les coordonnées en leur faisant subir la même transformation, n'est-ce pas ? Qu'en est-il
getComputedStyle(someElement).getPropertyValue('transform')
? Il semble renvoyer exactement une telle matrice. Je ne dis pas que les calculs matriciels sont faciles, mais ils sont précis et rapides...0 votes
@StijndeWitt Il y a une façon officielle de procéder dans les navigateurs, voir ma réponse.