Le scénario simple 1:1
Pour les situations où l'élément de toile est 1:1 par rapport à la taille du bitmap, vous pouvez obtenir les positions de la souris en utilisant ce snippet :
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
Il suffit de l'appeler depuis votre événement avec l'événement et le canevas comme arguments. Il retourne un objet avec x
y y
pour les positions de la souris.
Comme la position de la souris que vous obtenez est relative à la fenêtre du client, vous devrez soustraire la position de l'élément du canevas pour la convertir en position relative à l'élément lui-même.
Exemple d'intégration dans votre code :
// put this outside the event loop..
var canvas = document.getElementById("imgCanvas");
var context = canvas.getContext("2d");
function draw(evt) {
var pos = getMousePos(canvas, evt);
context.fillStyle = "#000000";
context.fillRect (pos.x, pos.y, 4, 4);
}
Note : Les bordures et le rembourrage affecteront la position s'ils sont appliqués directement à l'élément du canevas. getComputedStyle()
- ou d'appliquer ces styles à une div parent à la place.
Lorsque l'élément et le bitmap sont de tailles différentes
Lorsque la taille de l'élément est différente de celle de l'image bitmap, par exemple si l'élément est mis à l'échelle à l'aide d'une feuille de style CSS ou s'il existe un rapport pixel-aspect, etc.
Exemple :
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect(), // abs. size of element
scaleX = canvas.width / rect.width, // relationship bitmap vs. element for x
scaleY = canvas.height / rect.height; // relationship bitmap vs. element for y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
}
}
Avec des transformations appliquées au contexte (échelle, rotation, etc.)
Ensuite, il y a le cas plus compliqué où vous avez appliqué une transformation au contexte, comme une rotation, une inclinaison/un cisaillement, une mise à l'échelle, une translation, etc. Pour traiter ce cas, vous pouvez calculer la matrice inverse de la matrice actuelle.
Les navigateurs les plus récents vous permettent de lire la matrice actuelle via la fonction currentTransform
et Firefox (alpha actuel) fournit même une matrice inversée grâce à la propriété mozCurrentTransformInverted
. Firefox cependant, via mozCurrentTransform
retournera un tableau et non DOMMatrix
comme il se doit. Ni Chrome, lorsqu'il est activé par des drapeaux expérimentaux, ne renverra un message de type DOMMatrix
mais un SVGMatrix
.
Dans la plupart des cas, cependant, vous devrez mettre en œuvre une solution matricielle personnalisée (comme ma propre solution). aquí - projet free/MIT) jusqu'à ce qu'il obtienne un soutien total.
Lorsque vous aurez finalement obtenu la matrice, quel que soit le chemin emprunté pour l'obtenir, vous devrez l'inverser et l'appliquer aux coordonnées de votre souris. Les coordonnées sont ensuite transmises au canevas qui utilisera sa matrice pour les reconvertir où qu'elles se trouvent actuellement.
De cette façon, le point sera dans la position correcte par rapport à la souris. Ici aussi, vous devez ajuster les coordonnées (avant de leur appliquer la matrice inverse) pour qu'elles soient relatives à l'élément.
Un exemple montrant simplement les étapes de la matrice :
function draw(evt) {
var pos = getMousePos(canvas, evt); // get adjusted coordinates as above
var imatrix = matrix.inverse(); // get inverted matrix somehow
pos = imatrix.applyToPoint(pos.x, pos.y); // apply to adjusted coordinate
context.fillStyle = "#000000";
context.fillRect(pos.x-1, pos.y-1, 2, 2);
}
Un exemple d'utilisation currentTransform
lorsqu'elle sera mise en œuvre, le sera :
var pos = getMousePos(canvas, e); // get adjusted coordinates as above
var matrix = ctx.currentTransform; // W3C (future)
var imatrix = matrix.invertSelf(); // invert
// apply to point:
var x = pos.x * imatrix.a + pos.y * imatrix.c + imatrix.e;
var y = pos.x * imatrix.b + pos.y * imatrix.d + imatrix.f;
Mise à jour : J'ai créé une solution gratuite (MIT) pour intégrer toutes ces étapes dans un seul objet facile à utiliser, que l'on peut trouver à l'adresse suivante aquí et s'occupe également de quelques autres détails que la plupart des gens ignorent.