Jak dodać prostą obsługę zdarzenia onClick do elementu canvas?

Jestem doświadczonym programistą Java, ale patrzę na niektóre rzeczy JavaScript / HTML5 po raz pierwszy od około dekady. Nie wiem, co powinno być najprostsze.

Jako przykład chciałem coś narysować i dodać do tego obsługę zdarzenia. Jestem pewien, że robię coś głupiego, ale szukałem wszędzie i nic, co jest sugerowane (np. odpowiedź na to pytanie: Add onclick property to input with JavaScript ) nie działa. Używam Firefoksa 10.0.1. Mój kod jest następujący. Zobaczysz kilka skomentowanych linii, a na końcu każdego z nich znajduje się opis tego, co (lub co nie) się dzieje.

Jaka jest poprawna składnia? Wariuję!

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

Author: Community, 2012-03-27

7 answers

Gdy rysujesz do elementu canvas, po prostu rysujesz bitmapę w trybie natychmiastowym.

Elementy (kształty, linie, obrazy), które są rysowane, nie mają żadnej reprezentacji poza używanymi pikselami i ich kolorem.

Dlatego, aby uzyskać kliknij Zdarzenie na canvas element (kształt), musisz uchwycić zdarzenia kliknięcia na elemencie HTML canvas i użyć matematyki, aby określić, który element został kliknięty, pod warunkiem, że przechowujesz szerokość/wysokość elementów oraz przesunięcie x / y.

Aby dodać zdarzenie click do elementu canvas, użyj...

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

Aby określić, który element został kliknięty...

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 .

Ten kod dołącza Zdarzenie click do elementu canvas, a następnie wypycha jeden kształt (zwany element w moim kodzie) do tablicy elements. Możesz tu dodać tyle, ile chcesz.

Celem tworzenia tablicy obiektów jest sprawdzenie ich właściwości później. Po wypchnięciu wszystkich elementów na tablicę, wykonujemy pętlę i renderujemy każdy z nich na podstawie ich właściwości.

Po wywołaniu zdarzenia click, kod przecina elementy i określa, czy kliknięcie nastąpiło nad którymkolwiek z elementów tablicy elements. Jeśli tak, to uruchamia alert(), które można łatwo zmodyfikować, aby zrobić coś takiego, jak usunięcie elementu tablicy, w którym to przypadku potrzebujesz oddzielnej funkcji render , aby zaktualizować canvas.

Dla kompletność, dlaczego twoje próby nie zadziałały...

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

Jest to przypisanie wartości zwracanej alert() do właściwości onClick elem. Od razu przywołuje alert().

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

W JavaScript, ' i " są semantycznie identyczne, lexer prawdopodobnie używa ['"] do cudzysłowów.

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

Przypisujesz łańcuch do onClick właściwości elem.

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

JavaScript rozróżnia wielkość liter. Właściwość onclick jest archaiczną metodą dołączania obsługa zdarzeń. Pozwala na dołączenie tylko jednego zdarzenia z właściwością i zdarzenie może zostać utracone podczas serializacji HTML.

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

Jeszcze raz, ' === ".

 167
Author: alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-24 13:43:26

Polecam następujący artykuł: Hit Region Detection for HTML5 Canvas And How to Listen To Click Events On Canvas Shapes which goes through different situations.

Nie obejmuje jednak API addHitRegion, które musi być najlepszym sposobem(korzystanie z funkcji matematycznych i / lub porównań jest dość podatne na błędy). To podejście jest szczegółowe na dewelopera.mozilla

 2
Author: RUser4512,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-23 10:22:36

Jako alternatywa dla odpowiedzi Alexa:

Można użyć rysunku SVG zamiast rysunku Canvas. Tam można dodawać zdarzenia bezpośrednio do rysowanych obiektów DOM.

Zobacz na przykład:

Tworzenie obiektu obrazu svg, który można kliknąć za pomocą onclick, unikając bezwzględnego pozycjonowania

 1
Author: Goswin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:09

Można również umieścić elementy DOM, takie jak div Na wierzchu obszaru roboczego, które reprezentowałyby twoje elementy obszaru roboczego i były umieszczone w ten sam sposób.

Teraz możesz dołączyć słuchacze zdarzeń do tych Div I uruchomić niezbędne akcje.

 1
Author: Sergei Basharov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-31 16:22:06

Jako kolejna tania alternatywa na nieco statycznym płótnie, użycie nakładającego się elementu img z definicją usemap jest szybkie i brudne. Działa szczególnie dobrze na elementach płótna opartych na wielokątach, takich jak Wykres kołowy.

 0
Author: TadLewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-11 18:44:30

Prawdopodobnie bardzo późno na odpowiedź, ale właśnie przeczytałam to przygotowując się do egzaminu 70-480 i okazało się, że to działa -

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

Zwróć uwagę na zdarzenie jako onclick zamiast onClick.

Js Bin przykład.

 0
Author: Soham Dasgupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-22 19:36:38

Alex Answer jest całkiem zgrabna, ale podczas obracania kontekstu może być trudno prześledzić współrzędne x,y, więc zrobiłem Demo pokazujące, jak to śledzić.

Zasadniczo używam tej funkcji i podaję jej kąt i ilość przebytej odległości w tym Aniele przed narysowaniem obiektu.

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
Author: Imran Bughio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:09