it-swarm.com.de

Wie füge ich einem Canvas-Element einen einfachen onClick-Ereignishandler hinzu?

Ich bin ein erfahrener Java-Programmierer, schaue mir aber zum ersten Mal seit ungefähr einem Jahrzehnt etwas JavaScript/HTML5 an. Ich bin total verblüfft, was das einfachste überhaupt sein sollte.

Als Beispiel wollte ich nur etwas zeichnen und einen Event-Handler hinzufügen. Ich bin sicher, ich mache etwas Dummes, aber ich habe alles gesucht und nichts vorgeschlagen (z. B. die Antwort auf diese Frage): Fügen Sie die Eigenschaft onclick zur Eingabe mit JavaScript hinzu. Ich verwende Firefox 10.0.1. Mein Code folgt. Sie sehen mehrere kommentierte Zeilen und am Ende jeder Zeile wird beschrieben, was passiert (oder was nicht).

Was ist die richtige Syntax hier? Ich werde verrückt!

<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

Wenn Sie zu einem canvas-Element zeichnen, zeichnen Sie einfach eine Bitmap im Direktmodus .

Die gezeichneten Elemente (Formen, Linien, Bilder) haben neben den verwendeten Pixeln und ihrer Farbe keine Darstellung.

Um ein click -Ereignis für ein canvaselement (Shape) zu erhalten, müssen Sie Klickereignisse im canvas-HTML-Element erfassen und mithilfe von Mathematik bestimmen, welches Element angeklickt wurde Sie speichern die Breite/Höhe und den X/Y-Versatz der Elemente.

Um ein click-Ereignis zu Ihrem canvas-Element hinzuzufügen, verwenden Sie ...

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

Um zu bestimmen, auf welches Element geklickt wurde ...

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 .

Dieser Code hängt ein click -Ereignis an das canvas-Element an und schiebt dann eine Form (in meinem Code als element bezeichnet) in ein elements-Array. Sie können hier beliebig viele hinzufügen.

Das Erstellen eines Arrays von Objekten dient dazu, deren Eigenschaften später abzufragen. Nachdem alle Elemente auf das Array geschoben wurden, durchlaufen wir jedes Element und rendern es basierend auf ihren Eigenschaften.

Wenn das click-Ereignis ausgelöst wird, durchläuft der Code die Elemente und bestimmt, ob der Klick über einem der Elemente im elements-Array war. Wenn dies der Fall ist, wird eine alert() ausgelöst, die leicht geändert werden kann, um beispielsweise das Arrayelement zu entfernen. In diesem Fall benötigen Sie eine separate Funktion render, um die canvas zu aktualisieren.

Der Vollständigkeit halber, warum deine Versuche nicht funktionierten ...

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

Dies weist den Rückgabewert von alert() der onClick-Eigenschaft von elem zu. Es ruft sofort die alert() auf.

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

In JavaScript sind ' und " semantisch identisch, der Lexer verwendet ['"] wahrscheinlich für Anführungszeichen.

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

Sie weisen der onClick-Eigenschaft von elem eine Zeichenfolge zu.

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

JavaScript ist case sensitive. Die onclick-Eigenschaft ist die archaische Methode zum Anhängen von Ereignishandlern. Es kann nur ein Ereignis mit der Eigenschaft verknüpft werden, und das Ereignis kann beim Serialisieren des HTML-Codes verloren gehen.

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

Wieder ' === ".

180
alex

Ich empfehle den folgenden Artikel: Hit Region Detection für HTML5-Canvas und Anhören von Ereignissen auf Canvas-Formen die verschiedene Situationen durchläuft.

Die addHitRegion-API wird jedoch nicht behandelt. Dies muss der beste Weg sein (mathematische Funktionen und/oder Vergleiche sind ziemlich fehleranfällig). Dieser Ansatz ist detailliert auf auf developer.mozilla

3
RUser4512

Wahrscheinlich sehr spät zur Antwort, aber ich habe es gerade gelesen, während ich mich auf meine 70-480-Prüfung vorbereitete. 

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

Beachten Sie das Ereignis als onclick anstelle von onClick.

JS Bin Beispiel.

2
Soham Dasgupta

Sie können auch DOM-Elemente wie div auf die Leinwand setzen, die Ihre Leinwandelemente darstellen und auf dieselbe Weise positioniert werden. 

Jetzt können Sie diesen Divs Ereignis-Listener zuordnen und die erforderlichen Aktionen ausführen.

1
Sergei Basharov

Als Alternative zur Antwort von alex: 

Sie können eine SVG-Zeichnung anstelle einer Canvas-Zeichnung verwenden. Dort können Sie Ereignisse direkt zu den gezeichneten DOM-Objekten hinzufügen. 

siehe zum Beispiel:

Mit einem Klick ein SVG-Bildobjekt anklickbar machen, um absolute Positionierung zu vermeiden

1
Goswin

Als eine andere billige Alternative für eine etwas statische Leinwand ist die Verwendung eines überlagernden img-Elements mit einer Usemap-Definition schnell und schmutzig. Funktioniert besonders gut bei polygonbasierten Canvas-Elementen wie einem Kreisdiagramm.

0
TadLewis

Alex Answer ist ziemlich ordentlich, aber wenn Sie mit Hilfe von context drehen, kann es schwierig sein, x, y-Koordinaten zu finden, also habe ich eine Demo gemacht, die zeigt, wie man den Überblick behält.

Grundsätzlich verwende ich diese Funktion und gebe ihr den Winkel und die zurückgelegte Entfernung in diesem Engel, bevor das Objekt gezeichnet wird.

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