Як додати простий обробник подій 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.
ЛарШ

Ви можете скористатися цією lib 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.

Приклад Дж. С. Біна


3

Рекомендую наступну статтю: Виявлення регіону Hit для полотна HTML5 та прослуховування натискання подій на формах полотна, яке проходить через різні ситуації.

Однак він не охоплює addHitRegionAPI, що має бути найкращим способом (використання математичних функцій та / або порівнянь досить схильне до помилок). Цей підхід детально описаний на developer.mozilla


"[ addHitRegion] застарілий. Хоча він все ще може працювати в деяких браузерах, його використання не рекомендується використовувати, оскільки його можна буде видалити будь-коли. Спробуйте уникати його використання." - із посилання dev.moz, яке ви включаєте, щоб зберегти інші кліки.
Кріс

2

Як альтернатива відповіді Алекса:

Ви можете використовувати SVG-малюнок замість малюнка Canvas. Там ви можете додавати події безпосередньо до намальованих об’єктів DOM.

див. наприклад:

Здійснення натискання об’єкта зображення svg за допомогою onclick, уникаючи абсолютного позиціонування


1
вибачте за ентузіазм, просто у мене виникла проблема, для якої використання SVG є очевидним рішенням, і я не думав про це, поки ваш коментар ^^
Еліас Дорнелес

1

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

Тепер ви можете долучити слухачів подій до цих дівок та виконати необхідні дії.


1

В якості ще однієї дешевої альтернативи на дещо статичному полотні, використання елемента накладки img із визначенням Usemap є швидким та брудним. Особливо добре працює на елементах полотна на основі багатокутника, як кругова діаграма.


0

Алекс відповідь досить акуратний, але при використанні обертання контексту може бути важко простежити координати 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
    };
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.