web-dev-qa-db-ja.com

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

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

例として、何かを描き、イベントハンドラーを追加したかっただけです。私は愚かなことをしていると確信していますが、私はすべてを検索しましたが、提案されたものは何もありません(例えば、この質問に対する答え: 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>
112
Jer

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

描画されるelements(形状、線、画像)は、使用するピクセルと色以外の表現を持ちません。

したがって、canvaselement(shape)でclickイベントを取得するには、canvas HTML要素でクリックイベントをキャプチャし、数学を使用する必要があります要素の幅/高さとx/yオフセットを保存している場合、クリックされた要素を特定します。

clickイベントをcanvas要素に追加するには、...を使用します.

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

どのelementがクリックされたかを判断するには...

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

このコードは、clickイベントをcanvas要素にアタッチし、1つの図形(コードではelementと呼ばれます)をelements配列にプッシュします。ここに好きなだけ追加できます。

オブジェクトの配列を作成する目的は、後でプロパティをクエリできるようにすることです。すべての要素が配列にプッシュされた後、ループしてプロパティに基づいて各要素をレンダリングします。

clickイベントがトリガーされると、コードは要素をループし、elements配列の要素のいずれかをクリックしたかどうかを判断します。その場合、alert()を起動します。これは、配列項目を削除するなどの簡単な変更が可能です。この場合、canvasを更新するために別のrender関数が必要になります。

完全を期すため、あなたの試みがうまくいかなかった理由...

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

これは、alert()の戻り値をonClickelemプロパティに割り当てています。すぐにalert()を呼び出しています。

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

JavaScriptでは、'"は意味的に同一であり、レクサーはおそらく引用符に['"]を使用します。

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

onClickelemプロパティに文字列を割り当てています。

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

JavaScriptは大文字と小文字を区別します。 onclickプロパティは、イベントハンドラーをアタッチする古風な方法です。プロパティに関連付けられるイベントは1つのみであり、HTMLのシリアル化時にイベントが失われる可能性があります。

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

繰り返しますが、' === "

188
alex

次の記事をお勧めします: HTML5キャンバスのヒット領域検出と、キャンバスシェイプのクリックイベントをリッスンする方法 これはさまざまな状況を通過します。

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

3
RUser4512

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

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

イベントがonclickではなくonClickであることに注意してください。

JS Bin 例。

2
Soham Dasgupta

キャンバスの最上部にdivなどのDOM要素を配置して、キャンバス要素を表し、同じように配置することもできます。

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

1
Sergei Basharov

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

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

例を参照してください:

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

1
Goswin

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

0
TadLewis

Alex Answer はかなりきれいですが、コンテキストの回転を使用する場合、x、y座標をトレースするのが難しい場合があるため、 Demo を追跡する方法を示しました。

基本的に、私はこの関数を使用して、オブジェクトを描画する前にその天使に移動した角度と距離を与えます。

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