Как добавить простой обработчик событий onClick к элементу холста?

128

Я опытный программист на Java, но впервые примерно за десять лет смотрю на некоторые вещи, связанные с JavaScript / HTML5. Я совершенно не понимаю, что должно быть самым простым.

В качестве примера я просто хотел что-то нарисовать и добавить к нему обработчик событий. Я уверен, что делаю что-то глупое, но я искал повсюду, и ничего из предложенного (например, ответ на этот вопрос: добавить свойство onclick для ввода с помощью JavaScript ) не работает. Я использую Firefox 10.0.1. Мой код следует. Вы увидите несколько закомментированных строк, и в конце каждой будет описание того, что (или чего не происходит) происходит.

Какой здесь правильный синтаксис? Я схожу с ума!

<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
Использовать onclickвместоonClick
noob
1
Чтобы уточнить, почему эти попытки не сработали ... Первая пара комментариев немедленно отображает предупреждение, потому что вы вызываете alert()напрямую <script>, а не определяете функцию, которая будет вызывать alert(). Остальные ничего не делают из-за заглавных букв onclick.
LarsH
Вы можете использовать эту библиотеку jsfiddle.net/user/zlatnaspirala/fiddles , смотрите bitbucket.org/nikola_l/visual-js . Вы получите много возможностей +
Никола Лукич

Ответы:

223

Когда вы рисуете canvasэлемент, вы просто рисуете растровое изображение в немедленном режиме .

Эти элементы (формы, линия, изображения) , которые нарисованы не имеют никакого представления , кроме пикселей , которые они используют , и их цвет.

Следовательно, чтобы получить событие щелчка на canvas элементе (фигуре), вам необходимо захватить события щелчка на canvasэлементе HTML и использовать некоторые математические вычисления, чтобы определить, какой элемент был нажат, при условии, что вы сохраняете ширину / высоту элементов и смещение x / y. ,

Чтобы добавить clickсобытие к вашему canvasэлементу, используйте ...

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

Чтобы определить, какой элемент был нажат ...

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 .

Этот код прикрепляет clickсобытие к canvasэлементу, а затем подталкивает одну фигуру (называемую elementв моем коде) в elementsмассив. Вы можете добавить сюда сколько угодно.

Цель создания массива объектов - чтобы мы могли позже запросить их свойства. После того, как все элементы были помещены в массив, мы перебираем и визуализируем каждый из них на основе их свойств.

Когда clickсобытие запускается, код перебирает элементы и определяет, был ли щелчок по любому из элементов в elementsмассиве. Если это так, он запускает объект alert(), который можно легко изменить, чтобы сделать что-то, например удалить элемент массива, и в этом случае вам понадобится отдельная функция визуализации для обновления файла canvas.


Для полноты, почему ваши попытки не сработали ...

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

Это присвоение возвращаемого значения alert()к onClickсвойству elem. Он немедленно вызывает alert().

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

В JavaScript символы 'и "семантически идентичны, лексер, вероятно, использует их ['"]для кавычек.

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

Вы назначаете строку onClickсвойству elem.

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

JavaScript чувствителен к регистру. onclickСвойство является архаичным способом прикрепления обработчиков событий. Он позволяет прикрепить к свойству только одно событие, и событие может быть потеряно при сериализации HTML.

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

Опять же , ' === ".

Алекс
источник
Хм ... простите меня, если я неправильно понял - но разве я не фиксирую события щелчка на элементе холста? Я не уверен, что вы имеете в виду под тем, какой элемент был нажат. На этой странице только один элемент, верно?
Джер
Он имел в виду «какой элемент на холсте» - так сказать, какую «форму».
Йован Перович
1
Спасибо, очень, хотя я не совсем понимаю последний. Я следую примеру здесь: developer.mozilla.org/en/DOM/element.onclick (с использованием анонимной функции, которую они описывают), и он работает, даже когда я меняю диапазон на холст. Так что мне будет нетрудно постепенно преобразовать их пример в мой, чтобы увидеть, что я делаю неправильно. Спасибо за развернутый ответ! Особенно помогло объяснение того, почему мои различные попытки были ошибочными.
Джер
1
@Jer Не беспокойтесь, если у вас есть еще вопросы, не стесняйтесь писать и пинговать меня в Twitter, @alexdickson .
Alex
1
@HashRocketSyntax: Он должен работать нормально, просто обновите позиции ваших объектов в памяти и используйте эти определения для рендеринга
Alex
4

Наверное, очень поздно с ответом, но я просто прочитал это во время подготовки к 70-480экзамену и обнаружил, что это сработало -

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

Обратите внимание на событие как onclickвместо onClick.

Пример JS Bin .

Сохам Дасгупта
источник
3

Я рекомендую следующую статью: Обнаружение области совпадения для холста HTML5 и как прослушивать события щелчка на фигурах холста, которая проходит через различные ситуации.

Однако он не распространяется на addHitRegionAPI, который должен быть наилучшим (использование математических функций и / или сравнений весьма подвержено ошибкам). Этот подход подробно описан на сайте developer.mozilla.

RUser4512
источник
«[ addHitRegion] устарел. Хотя он все еще может работать в некоторых браузерах, его использование не рекомендуется, так как оно может быть удалено в любой момент. Старайтесь не использовать его». - по включенной вами ссылке dev.moz, чтобы сохранить щелчок для других.
Крис
2

В качестве альтернативы ответу Алексея:

Вы можете использовать рисунок SVG вместо рисунка холста. Там вы можете добавлять события прямо к нарисованным объектам DOM.

см. например:

Делаем объект изображения svg интерактивным с помощью onclick, избегая абсолютного позиционирования

Goswin
источник
1
извините за энтузиазм, просто у меня была проблема, для которой использование SVG - очевидное решение, и я не думал об этом до вашего комментария ^^
Элиас Дорнелес
1

Вы также можете разместить элементы DOM, например, divповерх холста, которые будут представлять ваши элементы холста и располагаться таким же образом.

Теперь вы можете прикрепить к этим блокам прослушиватели событий и выполнить необходимые действия.

Сергей Башаров
источник
1

В качестве еще одной дешевой альтернативы на несколько статичном холсте использование накладываемого элемента img с определением карты использования выполняется быстро и грязно. Особенно хорошо работает с элементами холста на основе многоугольников, такими как круговая диаграмма.

TadLewis
источник
0

Ответ Alex довольно удобен, но при использовании поворота контекста может быть сложно отследить координаты x, y, поэтому я сделал демонстрацию, показывающую, как это отслеживать.

В основном я использую эту функцию и задаю ей угол и расстояние, пройденное этим ангелом до рисования объекта.

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
    };
}
Имран Бугио
источник