Comment ajouter un gestionnaire d'événements simple onClick à un élément canvas?

je suis un programmeur Java expérimenté, mais je suis à la recherche de certaines choses JavaScript/HTML5 pour la première fois en environ une décennie. Je suis complètement perplexe sur ce qui devrait être la chose la plus simple.

comme 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 propriété onclick à entrer avec JavaScript ) travaux. J'utilise Firefox 10.0.1. Mon code suit. Vous verrez plusieurs lignes commentées et à la fin de chacune est une description de ce qui (ou ce qui ne) se produit pas.

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

98
demandé sur Community 2012-03-27 01:41:39

7 réponses

lorsque vous dessinez un élément canvas , vous dessinez simplement une image en mode mode immédiat .

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

par conséquent, pour obtenir un cliquez sur événement sur un canvas élément (forme), vous devez capturer cliquez les événements sur l'élément canvas HTML et utilisez quelques mathématiques pour déterminer quel élément a été cliqué, à condition que vous stockez la largeur/hauteur et le décalage x/Y.

pour ajouter un 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) à un tableau elements . Vous pouvez ajouter autant que vous voulez ici.

le but de créer un tableau d'objets est de pouvoir interroger leurs propriétés plus tard. Après que tous les éléments ont été poussés sur le tableau, nous bouclons et de rendre à chacun en fonction de leurs propriétés.

lorsque l'événement click est déclenché, le code boucle à travers les éléments et détermine si le clic était sur l'un des éléments dans le tableau elements . Si c'est le cas, il lance un alert() , qui pourrait facilement être modifié pour faire quelque chose comme supprimer l'élément du tableau, auquel cas vous auriez besoin d'une fonction render pour mettre à jour le canvas .

pour être complet, Pourquoi vos tentatives n'ont pas fonctionné...

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

c'est assignant la valeur de retour de alert() à la onClick propriété de elem . Elle invoque immédiatement le alert() .

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

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

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

vous assignez une chaîne de caractères à la onClick propriété de elem .

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

JavaScript est le cas sensible. La propriété onclick est la méthode archaïque de fixation des gestionnaires d'événements. Il permet seulement un événement d'être attaché à 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

de nouveau, ' === " .

167
répondu alex 2014-12-24 13:43:26

je recommande l'article suivant : a Frappé la Région de Détection Pour HTML5 Canvas Et Comment Écouter les Événements de Clic Sur Toile Formes , qui passe par différentes situations.

cependant, il ne couvre pas L'API addHitRegion , qui doit être le meilleur moyen (l'utilisation de fonctions mathématiques et/ou de comparaisons est assez sujette à erreur). Cette approche est détaillée sur le développeur.mozilla

2
répondu RUser4512 2018-02-23 10:22:36

comme alternative à la réponse d'alex:

vous pouvez utiliser un dessin SVG au lieu d'un dessin en toile. Vous pouvez y 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
répondu Goswin 2017-05-23 12:18:09

vous pouvez aussi placer des éléments DOM, comme div sur la toile qui représenteraient vos éléments de toile et seraient positionnés de la même façon.

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

1
répondu Sergei Basharov 2016-03-31 16:22:06

comme une autre alternative bon marché sur une toile quelque peu statique, en utilisant un élément img superposé avec une définition usemap est rapide et sale. Fonctionne particulièrement bien sur des éléments de toile à base de polygones comme un diagramme à secteurs.

0
répondu TadLewis 2018-04-11 18:44:30

probablement très tard à la réponse, mais je viens de lire ceci en préparant mon 70-480 examen, et j'ai trouvé cela à 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.

0
répondu Soham Dasgupta 2018-06-22 19:36:38

Alex Réponse est assez soigné, mais lors de l'utilisation d'un contexte rotation, il peut être difficile de retrouver la trace des coordonnées x,y, j'ai donc fait un Démo montrant comment garder une trace de ce.

fondamentalement, J'utilise cette fonction et je lui donne l'angle et la distance parcourue dans cet ange avant de dessiner l'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
    };
}
-1
répondu Imran Bughio 2017-05-23 12:18:09