304 votes

Comment obtenir les coordonnées d'un clic de souris sur un élément du canevas ?

Quelle est la manière la plus simple d'ajouter un gestionnaire d'événement de clic à un élément de toile qui renverra les coordonnées x et y du clic (par rapport à l'élément de toile) ?

Aucune compatibilité avec les anciens navigateurs n'est requise. Safari, Opera et Firefox font l'affaire.

1 votes

Cela ne devrait pas être différent de la réception des événements de souris des éléments normaux du domaine. quirksmode a une bonne référence à ce sujet.

4 votes

Le code que vous énumérez ci-dessus ne fonctionne que lorsque le canevas n'est pas profond à l'intérieur d'autres conteneurs. En général, vous devez utiliser quelque chose comme la fonction offset de jquery [var testDiv = $('#testDiv') ; var offset = testDiv.offset() ;] pour obtenir le décalage correct d'un navigateur à l'autre. C'est un vrai casse-tête.

0 votes

Le code affiché ci-dessus avec la mise à jour ne fonctionne pas si la page contenant la toile défile.

246voto

patriques Points 539

Si vous aimez la simplicité mais que vous voulez quand même une fonctionnalité multi-navigateurs, j'ai trouvé que cette solution était la meilleure pour moi. Il s'agit d'une simplification de la solution de @Aldekein mais sans jQuery .

function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    console.log("x: " + x + " y: " + y)
}

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})

0 votes

Si la page est défilée vers le bas, je suppose qu'il faut également prendre en compte le décalage de défilement du document.

8 votes

@PeppeL-G Le rectangle du client limite calcule cela pour vous. Vous pouvez facilement le tester en console avant de poster un commentaire (c'est ce que j'ai fait).

1 votes

@TomášZato, oh, getBoundingClientRect renvoie les positions par rapport au port de vue ? Alors ma supposition était fausse. Je ne l'ai jamais testé puisque cela n'a jamais été un problème pour moi, et je voulais gentiment avertir les autres lecteurs d'un problème potentiel que j'ai vu, mais je vous remercie pour votre clarification.

180voto

Ryan Artecona Points 1750

Mise à jour (5/5/16) : Réponse des patrons devrait être utilisé à la place, car il est à la fois plus simple et plus fiable.


Étant donné que le canevas n'est pas toujours stylé par rapport à l'ensemble de la page, la fonction canvas.offsetLeft/Top ne renvoie pas toujours ce dont vous avez besoin. Il renvoie le nombre de pixels qu'il est décalé par rapport à son élément offsetParent, ce qui peut être quelque chose comme un div contenant le canevas avec un position: relative appliqué. Pour tenir compte de cela, vous devez passer en boucle la chaîne de offsetParent en commençant par l'élément de toile lui-même. Ce code fonctionne parfaitement pour moi, testé dans Firefox et Safari mais devrait fonctionner pour tous.

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

La dernière ligne rend les choses plus pratiques pour obtenir les coordonnées de la souris par rapport à un élément du canevas. Tout ce qui est nécessaire pour obtenir les coordonnées utiles est

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;

0 votes

Est-ce que cela utilise le prototype de la bibliothèque ? Existe-t-il un moyen de le faire sans bibliothèque ?

8 votes

Non, il utilise l'objet prototype javascript intégré --- developer.mozilla.org/fr/

14 votes

Mon Chrome a event.offsetX y event.offsetY J'ai donc modifié votre solution en ajoutant if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; } . il semble que cela fonctionne.

83voto

N4ppeL Points 465

Edit 2018 : Cette réponse est assez ancienne et elle utilise des vérifications pour les anciens navigateurs qui ne sont plus nécessaires, comme le clientX y clientY fonctionnent dans tous les navigateurs actuels. Vous pouvez consulter Réponse de Patriques pour une solution plus simple et plus récente.

Réponse originale :
Comme décrit dans un article que j'ai trouvé à l'époque mais qui n'existe plus :

var x;
var y;
if (e.pageX || e.pageY) { 
  x = e.pageX;
  y = e.pageY;
}
else { 
  x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
  y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

Ça a parfaitement fonctionné pour moi.

32 votes

Cette solution ne fonctionne pas toujours - la réponse de Ryan Artecona fonctionne dans le cas plus général où le canevas n'est pas nécessairement positionné par rapport à l'ensemble de la page.

3 votes

Cette solution n'est pas adaptée si les performances sont importantes, puisque les accès Dom sont effectués à chaque clic/déplacement. Et getBoundingClientRect existe maintenant, et est plus élégant.

18voto

Aldekein Points 408

Selon des données fraîches Quirksmode le site clientX y clientY sont prises en charge par tous les principaux navigateurs. Voici donc le bon code qui fonctionne dans un div défilant sur une page avec des barres de défilement :

function getCursorPosition(canvas, event) {
var x, y;

canoffset = $(canvas).offset();
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left);
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;

return [x,y];
}

Cela nécessite également jQuery pour $(canvas).offset() .

0 votes

Equivalent de la réponse de @N4ppeL.

13voto

J'ai fait une démonstration complète qui fonctionne dans tous les navigateurs avec le code source complet de la solution de ce problème : Coordonnées d'un clic de souris sur Canvas en Javascript . Pour essayer la démo, copiez le code et collez-le dans un éditeur de texte. Enregistrez-le ensuite sous le nom de example.html et, enfin, ouvrez le fichier avec un navigateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X