Come faccio ad aggiungere un semplice gestore di eventi onClick a un elemento canvas?


128

Sono un programmatore Java esperto, ma sto guardando alcune cose JavaScript / HTML5 per la prima volta in circa un decennio. Sono completamente perplesso su quella che dovrebbe essere la cosa più semplice di sempre.

Ad esempio, volevo solo disegnare qualcosa e aggiungere un gestore di eventi. Sono sicuro che sto facendo qualcosa di stupido, ma ho cercato dappertutto e nulla di ciò che viene suggerito (ad esempio la risposta a questa domanda: Aggiungi proprietà onclick per inserire con JavaScript ) funziona. Sto usando Firefox 10.0.1. Il mio codice segue. Vedrai diverse righe commentate e alla fine di ognuna c'è una descrizione di cosa (o cosa non succede).

Qual è la sintassi corretta qui? Sto impazzendo!

<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>


8
Usa onclickinvece dionClick
noob il

1
Per approfondire il motivo per cui questi tentativi non hanno funzionato ... Il primo paio di commenti visualizza immediatamente un avviso perché stai chiamando alert()direttamente <script>, invece di definire una funzione che chiamerà alert(). Il resto non fa nulla a causa della capitalizzazione di onclick.
LarsH,

Puoi usare questa lib jsfiddle.net/user/zlatnaspirala/fiddles , guarda bitbucket.org/nikola_l/visual-js . Avrai molte funzionalità +
Nikola Lukic

Risposte:


223

Quando disegni a un canvaselemento, stai semplicemente disegnando una bitmap in modalità immediata .

Gli elementi (forme, linee, immagini) che vengono disegnati non hanno rappresentazione oltre ai pixel che usano e al loro colore.

Pertanto, per ottenere un evento clic su un canvas elemento (forma), è necessario acquisire eventi clic sul filecanvas HTML e utilizzare alcuni calcoli per determinare quale elemento è stato selezionato, a condizione che si stiano memorizzando la larghezza / altezza degli elementi e l'offset x / y .

Per aggiungere un clickevento al tuo canvaselemento, usa ...

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

Per determinare quale elemento è stato fatto clic ...

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 .

Questo codice collega un clickevento canvasall'elemento, quindi inserisce una forma (chiamata an elementnel mio codice) in un elementsarray. Puoi aggiungerne quanti ne desideri qui.

Lo scopo della creazione di una matrice di oggetti è così che possiamo interrogare le loro proprietà in un secondo momento. Dopo che tutti gli elementi sono stati inseriti nell'array, eseguiamo il loop e il rendering di ognuno in base alle loro proprietà.

Quando clickviene attivato l' evento, il codice scorre attraverso gli elementi e determina se il clic si trova su uno degli elementi elementsdell'array. In tal caso, genera un alert(), che potrebbe essere facilmente modificato per fare qualcosa come rimuovere l'elemento dell'array, nel qual caso avresti bisogno di una funzione di rendering separata per aggiornare il canvas.


Per completezza, perché i tuoi tentativi non hanno funzionato ...

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

Questo sta assegnando il valore restituito alert()alla onClickproprietà di elem. Richiama immediatamente il alert().

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

In JavaScript, 'e "sono semanticamente identici, il lexer probabilmente usa ['"]per le virgolette.

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

Stai assegnando una stringa alla onClickproprietà di elem.

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

JavaScript fa distinzione tra maiuscole e minuscole. La onclickproprietà è il metodo arcaico di associare i gestori di eventi. Consente solo un evento da associare alla proprietà e l'evento può essere perso durante la serializzazione dell'HTML.

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

Nuovamente, ' === ".


Hmm ... perdonami se non capisco, ma non sto catturando eventi di click sull'elemento canvas? Non sono sicuro di cosa intendi con quale elemento è stato cliccato. C'è solo un elemento in questa pagina, giusto?
Jer

Intendeva "quale elemento all'interno della tela" - cioè quale "forma" per così dire.
Jovan Perovic,

1
Grazie, anche se non sono del tutto chiaro sull'ultimo. Sto seguendo l'esempio qui: developer.mozilla.org/en/DOM/element.onclick (utilizzando la funzione anonima che descrivono) e funziona, anche quando cambio l'intervallo in un'area di disegno. Quindi non sarà difficile per me trasformare lentamente il loro esempio nel mio per vedere cosa sto facendo di sbagliato. Grazie per la risposta dettagliata! La spiegazione del perché i miei vari tentativi erano sbagliati è stata particolarmente utile.
Jer

1
@Jer Non preoccuparti, se hai altre domande, sentiti libero di postare e fare ping su Twitter, @alexdickson .
alex

1
@HashRocketSyntax Dovrebbe funzionare bene, basta aggiornare le posizioni dei tuoi oggetti in memoria e usare quelle definizioni per renderizzare da
alex

4

Probabilmente molto tardi alla risposta, ma ho appena letto questo mentre mi preparavo per il mio 70-480esame e ho scoperto che funzionava -

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

Notare l'evento come onclickanziché onClick.

Esempio di bin JS .


3

Consiglio il seguente articolo: Hit Region Detection for HTML5 Canvas e come ascoltare gli eventi Click On Canvas Shapes che attraversano varie situazioni.

Tuttavia, non copre l' addHitRegionAPI, che deve essere il modo migliore (l'utilizzo di funzioni matematiche e / o confronti è piuttosto soggetto a errori). Questo approccio è dettagliato su developer.mozilla


"[ addHitRegion] è obsoleto. Sebbene possa ancora funzionare in alcuni browser, il suo uso è sconsigliato poiché potrebbe essere rimosso in qualsiasi momento. Cerca di evitare di usarlo." - dal link dev.moz che includi, per salvare gli altri un clic.
Chris,


1

Puoi anche mettere elementi DOM, come divsopra la tela che rappresenterebbero i tuoi elementi della tela e sarebbero posizionati allo stesso modo.

Ora puoi associare listener di eventi a questi div ed eseguire le azioni necessarie.


1

Come altra alternativa economica su canvas in qualche modo statico, l'uso di un elemento img sovrapposto con una definizione di mappa d'uso è rapido e sporco. Funziona particolarmente bene su elementi canvas poligonali come un grafico a torta.


0

La risposta di Alex è piuttosto ordinata ma quando si usa la rotazione del contesto può essere difficile tracciare le coordinate x, y, quindi ho creato una demo che mostra come tenerne traccia.

Fondamentalmente sto usando questa funzione e dandogli l'angolo e la quantità di distanza percorsa in quell'angelo prima di disegnare l'oggetto.

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
    };
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.