読者です 読者をやめる 読者になる 読者になる

tsujimotterのノートブック

日曜数学者 tsujimotter の「趣味で数学」実践ノート

jQuery で canvas をクリックするときの注意

Boids Sim を作ってる最中に表題に関してハマったのでメモがてら書いておきます。

参考:Boids を使って新感覚ブラウザゲームを作ってみた - tsujimotterのノートブック

やりたかったことは、html5 の canvas にクリックイベントを追加することです。



そこで最初、次のようなコードを書きました。

$(function() {
    // クリック処理
    $('canvas').click( function(event){
        var x = event.pageX;
        var y = event.pageY;

        /* ここに x, y を使った処理 */
    });
});

しかし、これではうまくいかないことがあります。
それは、canvas の左上座標がぴったり document の左上に一致しない場合です。jQuery の event.pageX, event.pageY は 取得したキャンバスの 左上からの相対座標ではなく、document 上の 絶対座標となっているためです。

次の図のようなイメージです。

f:id:tsujimotter:20131129025656p:plain

そこで、キャンバスの左上座標を取得しておいて、差し引いてあげればよいですね。

$(function() {
    // 最初に canvas の左上座標を取得しておく
    var rect = $('canvas').offset();

    // クリック処理
    $('canvas').click( function(event){
        var x = event.pageX - rect.left;
        var y = event.pageY - rect.top;

        /* ここに x, y を使った処理 */
    });
});

「これで完璧!」と思うかもしれませんが、残念ながらまだ十分ではありません。といいつつも、私自身もこれでオーケーかと思っていました。。

実はこのコードでは、キャンバスの位置が移動してしまった場合を考慮できていません。DOM上でキャンバスの上にあるオブジェクトのサイズが変わったり、新たに show() された場合などの状況が想定されます。また、ブラウザのサイズがユーザーによって変えられてレイアウトが変わってしまった状況も考えられるでしょう。

対策は非常に簡単です。
毎回、クリックイベントの度に左上座標を取得すればよいのです。

完成形のコードを以下に示します。

$(function() {
    // クリック処理
    $('canvas').click( function(event){
        // クリックの度に canvas の左上座標を取得する
        var rect = $(event.target).offset();
    
        var x = event.pageX - rect.left;
        var y = event.pageY - rect.top;

        /* ここに x, y を使った処理 */
    });
});

ちなみに、event.target で イベント発生元のオブジェクト(この場合 canvas) の jQuery オブジェクトを取得できるので、覚えておくといいでしょう。

追記

StackOverflowの次のページも参考になります。

getting the X/Y coordinates of a mouse click on an image with jQuery - Stack Overflow