web-dev-qa-db-fra.com

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

Je suis un programmeur expérimenté en Java, mais je suis en train de regarder quelques éléments JavaScript/HTML5 pour la première fois depuis environ une décennie. Je suis complètement perplexe sur ce qui devrait être la chose la plus simple de tous les temps.

Par exemple, je voulais juste 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 qui est suggéré (par exemple la réponse à cette question: Ajouter la propriété onclick pour entrer avec JavaScript ) fonctionne. J'utilise Firefox 10.0.1. Mon code suit. Vous verrez plusieurs lignes commentées et à la fin de chacune se trouve une description de ce qui se passe (ou de ce qui ne se passe pas).

Quelle est la syntaxe correcte ici? Je deviens 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>

105
Jer

Lorsque vous dessinez un élément canvas, vous dessinez simplement une image bitmap dans mode immédiat .

Les éléments (formes, lignes, images) dessinés n'ont aucune représentation en dehors des pixels qu'ils utilisent et de leur couleur.

Par conséquent, pour obtenir un événement click sur une canvasélément (forme), vous devez capturer des événements de clic sur l’élément HTML canvas et utiliser des calculs mathématiques pour déterminer l’élément sur lequel vous avez cliqué, à condition que vous stockiez les éléments. éléments 'largeur/hauteur et décalage x/y.

Pour ajouter un événement click à votre élément canvas, utilisez ...

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

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

var elem = document.getElementById('myCanvas'),
    elemLeft = elem.offsetLeft,
    elemTop = elem.offsetTop,
    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 événement click à l'élément canvas, puis pousse une forme (appelée element dans mon code) dans un tableau elements. Vous pouvez en ajouter autant que vous le souhaitez ici.

La création d’un tableau d’objets a pour but de pouvoir interroger leurs propriétés ultérieurement. Une fois que tous les éléments ont été placés sur le tableau, nous les parcourons et les rendons en fonction de leurs propriétés.

Lorsque l'événement click est déclenché, le code parcourt les éléments et détermine si le clic a été effectué sur l'un des éléments du tableau elements. Si tel est le cas, il déclenche une alert(), qui pourrait facilement être modifiée pour supprimer le tableau, ce qui nécessiterait une fonction render distincte pour mettre à jour la canvas.

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

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

Ceci affecte la valeur de retour de alert() à la propriété onClick de elem. Il appelle immédiatement la alert().

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

En JavaScript, ' et " sont sémantiquement identiques, le lexer utilise probablement ['"] pour les guillemets.

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

Vous affectez une chaîne à la propriété onClick de elem.

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

JavaScript est sensible à la casse. La propriété onclick est la méthode archaïque d’attachement de gestionnaires d’événements. Il ne permet d'associer qu'un seul événement à la propriété et cet événement peut être perdu lors de la sérialisation du code HTML.

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

Encore une fois, ' === ".

180
alex

Je recommande l'article suivant: Détection de la région ciblée pour le canevas HTML5 et comment écouter les événements de clic sur les formes du canevas qui passe par diverses situations.

Cependant, il ne couvre pas l'API addHitRegion, qui doit être la meilleure solution (l'utilisation de fonctions mathématiques et/ou de comparaisons est assez sujette aux erreurs). Cette approche est détaillée sur developer.mozilla

3
RUser4512

Probablement très tard pour la réponse, mais je viens de lire ceci en préparant mon examen 70-480 et j'ai trouvé que cela fonctionnait 

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

Notez l'événement en tant que onclick au lieu de onClick.

JS Bin exemple.

2
Soham Dasgupta

Vous pouvez également placer des éléments DOM, tels que div, sur le canevas, qui représenteraient vos éléments de canevas et seraient positionnés de la même manière. 

Vous pouvez maintenant attacher des écouteurs d'événements à ces divs et exécuter les actions nécessaires.

1
Sergei Basharov

Comme alternative à la réponse d'Alex: 

Vous pouvez utiliser un dessin SVG au lieu d'un dessin Canvas. Là, vous pouvez 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

1
Goswin

En tant qu'alternative peu coûteuse sur un canevas quelque peu statique, l'utilisation d'un élément img superposé avec une définition de carte d'usin est rapide et sale. Fonctionne particulièrement bien sur les éléments de canevas basés sur des polygones, comme un graphique à secteurs.

0
TadLewis

Alex Answer est assez soigné, mais lorsque vous utilisez la rotation de contexte, il peut être difficile de tracer les coordonnées x, y. J'ai donc créé une Demo montrant comment en tenir compte.

En gros, j'utilise cette fonction et lui donne l'angle et la distance parcourue dans cet ange avant de dessiner un objet.

function rotCor(angle, length){
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);

    var newx = length*cos;
    var newy = length*sin;

    return {
        x : newx,
        y : newy
    };
}
0
Imran Bughio