単純なonClickイベントハンドラーをcanvas要素に追加するにはどうすればよいですか?


128

私は経験豊富なJavaプログラマーですが、JavaScript / HTML5関連のものを約10年ぶりに検討しています。私はこれまでで最も簡単なものであるべきものに完全に困惑しています。

例として、何かを描き、それにイベントハンドラを追加したかっただけです。私は愚かなことをしていると確信していますが、私はすべてを検索しましたが、何も提案されていません(たとえば、この質問への回答: JavaScriptで入力するonclickプロパティを追加)は機能します。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
それらの試みがうまくいかなかった理由を詳しく説明すると...最初の2つのコメントalert()<script>、を呼び出す関数を定義するのではなく、で直接呼び出しているため、すぐにアラートを表示しますalert()。の大文字のため、残りは何もしませんonclick
LarsH 2016

このlib jsfiddle.net/user/zlatnaspirala/fiddlesを使用できます。bitbucket.org/ nikola_l / visual-jsを参照してください。多くの機能が追加されます+
Nikola Lukic

回答:


223

canvas要素に描画するときは、ビットマップをイミディエイトモードで描画するだけです

要素描かれている(図形、線、イメージ)は、それらが使用画素とその色以外に何の表現を持っていません。

そのため、取得するにはクリックでイベントをcanvas 要素(形状)、あなたは上のクリックイベントキャプチャする必要があるcanvasHTML要素をし、クリックされた要素を決定するためにいくつかの数学を使用し、あなたはオフセット要素の幅/高さとの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要素にアタッチし、1つの形状(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プロパティには、イベントハンドラを取り付ける古風な方法です。プロパティにアタッチできるイベントは1つだけで、HTMLをシリアル化するとイベントが失われる可能性があります。

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

ここでも、' === "


うーん...私が誤解している場合は許してください-しかし、私はキャンバス要素のクリックイベントをキャプチャしていませんか?クリックされ要素の意味がわかりません。このページの要素は1つだけですよね?
Jer

彼は「キャンバス内のどの要素」、つまりいわば「形状」を意味していました。
Jovan Perovic

1
どうもありがとうございます。最後の1つは完全にはわかりませんが。私はここの例に従っています: developer.mozilla.org/en/DOM/element.onclick(彼らが説明している無名関数を使用しています)。スパンをキャンバスに変更しても、それは機能します。したがって、私が彼らの例をゆっくりと私のものに変えて、私が間違っていることを確認することは難しくありません。細かい対応ありがとうございます!私のさまざまな試みが間違っていた理由の説明は特に役に立ちました。
Jer

1
@Jer心配ありません。他に質問がある場合は、@ alexdicksonでTwitterに投稿してpingしてください。
アレックス

1
@HashRocketSyntax正常に動作するはずです。メモリ内のオブジェクトの位置を更新し、それらの定義を使用してレンダリングします
アレックス

4

おそらく回答に非常に遅れていますが、私は70-480試験の準備中にこれを読んだだけで、これが機能することがわかりました-

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

onclick代わりにイベントに注意してくださいonClick

JS Binの例。


3

次の記事をお勧めします:HTML5 Canvasのヒット領域検出と、さまざまな状況を経るCanvas ShapesのClickイベントをリッスンする方法

ただし、これはaddHitRegion最良の方法であるAPIをカバーしていません(数学関数や比較を使用するとエラーが発生しやすくなります)。このアプローチはdeveloper.mozillaで詳しく説明されています


「[ addHitRegion]は廃止されています。一部のブラウザーでは引き続き機能する可能性がありますが、いつでも削除される可能性があるため、使用しないことをお勧めします。使用しないようにしてください。」-含めるdev.mozリンクから、他の人のクリックを保存します。
Chris

2

アレックスの答えの代わりとして:

Canvas図面の代わりにSVG図面を使用できます。そこで、描画されたDOMオブジェクトに直接イベントを追加できます。

例を参照してください:

onclickでsvg画像オブジェクトをクリック可能にし、絶対配置を回避する


1
熱狂して申し訳ありませんが、SVGの使用が明白な解決策であるという問題が発生しただけです。コメントまでは考えていませんでした^^
エリアスドルネレス

1

divキャンバス要素を表し、同じ方法で配置されるキャンバスの上などに、DOM要素を配置することもできます。

これで、これらのdivにイベントリスナーをアタッチして、必要なアクションを実行できます。


1

やや静的なキャンバスでのもう1つの安価な代替手段として、オーバーレイするimg要素をusemap定義で使用するのは速くて汚いです。円グラフのようなポリゴンベースのキャンバス要素で特にうまく機能します。


0

Alex Answerはすっきりしていますが、コンテキスト回転を使用すると、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
    };
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.