159 votes

Comment ajouter un simple gestionnaire d'événement onClick à un élément de toile ?

Je suis un programmeur Java expérimenté, mais je me penche pour la première fois depuis une dizaine d'années sur les technologies JavaScript/HTML5. Je suis complètement désemparé face à ce qui devrait être la chose la plus simple qui soit.

Par exemple, je voulais simplement dessiner quelque chose et y ajouter un gestionnaire d'événements. Je suis sûr que je fais quelque chose de stupide, mais j'ai cherché partout et rien de ce qui est suggéré (par exemple, la réponse à cette question : Ajouter la propriété onclick à une entrée avec JavaScript ) fonctionne. J'utilise Firefox 10.0.1. Mon code suit. Vous verrez plusieurs lignes commentées et, à la fin de chacune, une description de ce qui se passe (ou ne se passe pas).

Quelle est la syntaxe correcte ici ? Je suis en train de devenir fou !

<html>
<body>
    <canvas id="myCanvas" width="300" height="150"/>
    <script language="JavaScript">
        var elem = document.getElementById('myCanvas');
        // elem.onClick = alert("hello world");  - displays alert without clicking
        // elem.onClick = alert('hello world');  - displays alert without clicking
        // elem.onClick = "alert('hello world!')";  - does nothing, even with clicking
        // elem.onClick = function() { alert('hello world!'); };  - does nothing
        // elem.onClick = function() { alert("hello world!"); };  - does nothing
        var context = elem.getContext('2d');
        context.fillStyle = '#05EFFF';
        context.fillRect(0, 0, 150, 100);
    </script>

</body>

12 votes

Utilice onclick au lieu de onClick

2 votes

Pour expliquer pourquoi ces tentatives n'ont pas fonctionné... Les deux premiers commentaires affichent immédiatement une alerte parce que vous appelez alert() directement dans <script> au lieu de définir une fonction qui appelle alert() . Le reste ne fait rien à cause de la majuscule de onclick .

0 votes

Vous pouvez utiliser cette librairie jsfiddle.net/user/zlatnaspirala/fiddles , regarde bitbucket.org/nikola_l/visual-js . Vous obtiendrez de nombreuses fonctionnalités +

263voto

alex Points 186293

Lorsque vous tirez sur un canvas vous dessinez simplement un bitmap dans l'élément mode immédiat .

Le site éléments (formes, lignes, images) qui sont dessinées n'ont pas de représentation autre que les pixels qu'elles utilisent et leur couleur.

Par conséquent, pour obtenir un cliquez sur sur un canvas élément (forme), vous devez capturer les événements de clic sur l'icône canvas HTML et utiliser des calculs pour déterminer l'élément sur lequel on a cliqué, à condition de stocker la largeur/hauteur et le décalage x/y des éléments.

Pour ajouter un click à votre canvas élément, utiliser...

canvas.addEventListener('click', function() { }, false);

Pour déterminer quels élément a été cliqué...

var elem = document.getElementById('myCanvas'),
    elemLeft = elem.offsetLeft + elem.clientLeft,
    elemTop = elem.offsetTop + elem.clientTop,
    context = elem.getContext('2d'),
    elements = [];

// Add event listener for `click` events.
elem.addEventListener('click', function(event) {
    var x = event.pageX - elemLeft,
        y = event.pageY - elemTop;

    // Collision detection between clicked offset and element.
    elements.forEach(function(element) {
        if (y > element.top && y < element.top + element.height 
            && x > element.left && x < element.left + element.width) {
            alert('clicked an element');
        }
    });

}, false);

// Add element.
elements.push({
    colour: '#05EFFF',
    width: 150,
    height: 100,
    top: 20,
    left: 15
});

// Render elements.
elements.forEach(function(element) {
    context.fillStyle = element.colour;
    context.fillRect(element.left, element.top, element.width, element.height);
});

jsFiddle .

Ce code attache un click à l'événement canvas puis pousse une forme (appelée élément element dans mon code) à un elements réseau. Vous pouvez en ajouter autant que vous le souhaitez ici.

La création d'un tableau d'objets a pour but de nous permettre d'interroger leurs propriétés ultérieurement. Une fois que tous les éléments ont été placés dans le tableau, nous bouclons et rendons chacun d'entre eux en fonction de leurs propriétés.

Lorsque le click est déclenché, le code passe en boucle les éléments et détermine si le clic a été effectué sur l'un des éléments de l'élément elements tableau. Si c'est le cas, il déclenche un alert() qui pourrait facilement être modifié pour faire quelque chose comme supprimer l'élément du tableau, auquel cas vous auriez besoin d'un fichier séparé Rendu pour mettre à jour le canvas .


Pour être complet, pourquoi vos tentatives n'ont pas fonctionné...

elem.onClick = alert("hello world"); // displays alert without clicking

Cela revient à assigner la valeur de retour de alert() à la onClick propriété de elem . Il invoque immédiatement le alert() .

elem.onClick = alert('hello world');  // displays alert without clicking

En JavaScript, le ' y " sont sémantiquement identiques, le lexeur utilise probablement ['"] pour les citations.

elem.onClick = "alert('hello world!')"; // does nothing, even with clicking

Vous attribuez une chaîne de caractères à l'élément onClick propriété de elem .

elem.onClick = function() { alert('hello world!'); }; // does nothing

JavaScript est sensible à la casse. Le site onclick est la méthode archaïque pour attacher des gestionnaires d'événements. Elle ne permet de joindre qu'un seul événement à la propriété et l'événement peut être perdu lors de la sérialisation du HTML.

elem.onClick = function() { alert("hello world!"); }; // does nothing

Encore une fois, ' === " .

0 votes

Hmm... pardonnez-moi si je ne comprends pas bien - mais est-ce que je ne capture pas les événements de clic sur l'élément de la toile ? Je ne suis pas sûr de ce que vous voulez dire par ce que a été cliqué. Il n'y a qu'un seul élément sur cette page, non ?

0 votes

Il voulait dire "quel élément dans la toile" - c'est-à-dire quelle "forme" pour ainsi dire.

0 votes

@jperovic C'est exactement comme ça que j'ai écrit ma réponse, j'ai juste appelé une forme un élément dans cet exemple. C'est peut-être le mauvais mot, c'est un peu ambigu.

26voto

freestock.tk Points 4288

2021 :

Pour créer un élément traçable, vous devez utiliser la fonction nouveau Path2D() método.

Vous devez écouter les événements de souris sur votre toile pour obtenir les coordonnées du point (souris), puis utiliser CanvasRenderingContext2D.isPointInPath() o CanvasRenderingContext2D.isPointInStroke() pour vérifier précisément si la souris se trouve sur votre élément.

IsPointInPath :

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Create circle
const circle = new Path2D();
circle.arc(150, 75, 50, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circle);

// Listen for mouse moves
canvas.addEventListener('mousemove', function(event) {
  // Check whether point is inside circle
  if (ctx.isPointInPath(circle, event.offsetX, event.offsetY)) {
    ctx.fillStyle = 'green';
  }
  else {
    ctx.fillStyle = 'red';
  }

  // Draw circle
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fill(circle);
});

<canvas id="canvas"></canvas>

IsPointInStroke :

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Create ellipse
const ellipse = new Path2D();
ellipse.ellipse(150, 75, 40, 60, Math.PI * .25, 0, 2 * Math.PI);
ctx.lineWidth = 25;
ctx.strokeStyle = 'red';
ctx.fill(ellipse);
ctx.stroke(ellipse);

// Listen for mouse moves
canvas.addEventListener('mousemove', function(event) {
  // Check whether point is inside ellipse's stroke
  if (ctx.isPointInStroke(ellipse, event.offsetX, event.offsetY)) {
    ctx.strokeStyle = 'green';
  }
  else {
    ctx.strokeStyle = 'red';
  }

  // Draw ellipse
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fill(ellipse);
  ctx.stroke(ellipse);
});

<canvas id="canvas"></canvas>

Exemple avec plusieurs éléments :

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const circle = new Path2D();
circle.arc(50, 75, 50, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circle);

const circletwo = new Path2D();
circletwo.arc(200, 75, 50, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circletwo);

// Listen for mouse moves
canvas.addEventListener('mousemove', function(event) {
  // Check whether point is inside circle
  if (ctx.isPointInPath(circle, event.offsetX, event.offsetY)) {
    ctx.fillStyle = 'green';
    ctx.fill(circle);
  }
  else {
    ctx.fillStyle = 'red';
    ctx.fill(circle);
  }

    if (ctx.isPointInPath(circletwo, event.offsetX, event.offsetY)) {
    ctx.fillStyle = 'blue';
    ctx.fill(circletwo);
  }
  else {
    ctx.fillStyle = 'red';
    ctx.fill(circletwo);
  }

});

html {cursor: crosshair;}

<canvas id="canvas"></canvas>

Si vous avez une liste d'éléments dynamiques à vérifier, vous pouvez les vérifier dans une boucle, comme ceci :

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var elementslist = []

const circle = new Path2D();
circle.arc(50, 75, 30, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circle);

const circletwo = new Path2D();
circletwo.arc(150, 75, 30, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circletwo);

const circlethree = new Path2D();
circlethree.arc(250, 75, 30, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill(circlethree);

elementslist.push(circle,circletwo,circlethree)

document.getElementById("canvas").addEventListener('mousemove', function(event) {
event = event || window.event;
var ctx = document.getElementById("canvas").getContext("2d")

for (var i = window.elementslist.length - 1; i >= 0; i--){  

if (window.elementslist[i] && ctx.isPointInPath(window.elementslist[i], event.offsetX, event.offsetY)) {
document.getElementById("canvas").style.cursor = 'pointer';
    ctx.fillStyle = 'orange';
    ctx.fill(window.elementslist[i]);
return
} else {
document.getElementById("canvas").style.cursor = 'default';
    ctx.fillStyle = 'red';
    for (var d = window.elementslist.length - 1; d >= 0; d--){ 
    ctx.fill(window.elementslist[d]);
    }
}
}  

});

<canvas id="canvas"></canvas>

Sources : https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInPath & https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/isPointInStroke

4voto

Soham Dasgupta Points 750

Je ne réponds probablement que tardivement, mais je viens de lire ceci alors que je préparais mon 70-480 et j'ai trouvé ceci pour travailler -

var elem = document.getElementById('myCanvas');
elem.onclick = function() { alert("hello world"); }

Notez l'événement comme onclick au lieu de onClick .

JS Bin exemple.

3voto

Goswin Points 615

Comme alternative à la réponse d'Alex :

Vous pourriez utiliser un dessin SVG au lieu d'un dessin Canvas. Vous pouvez alors ajouter des événements directement aux objets DOM dessinés.

voir par exemple :

Rendre un objet image svg cliquable avec onclick, en évitant le positionnement absolu

3voto

RUser4512 Points 531

Je recommande l'article suivant : Détection des zones de frappe pour HTML5 Canvas et comment écouter les événements de clics sur les formes Canvas qui passe par diverses situations.

Toutefois, il ne couvre pas le addHitRegion qui doit être le meilleur moyen (l'utilisation de fonctions mathématiques et/ou de comparaisons est sujette à des erreurs). Cette approche est détaillée sur developer.mozilla

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