| JavaScriptでイベント処理 |
CANVASなどの対象となる要素上でクリックなどを行った時のイベント処理方法について確認してみます。今回は、JavaScriptの「addEventListener()」を使ってイベント処理を行います。「addEventListener()」は、クリックなどのマウス操作、タッチパネルへのタッチ操作、キーボード操作などのイベントを監視し、イベントが発生時に対応する処理を実行するものです。下記の様に記載します。
| 対象要素.addEventListener( ①種類 , ②関数 , ③false ) |
①は、“click” などイベント種類、②は実行する関数、③はウィンドウからイベントターゲットの親までのイベント取得フェーズ(“true”/キャプチャフェーズ 、“false”/バブリングフェーズ)を指定します。
| “click”イベントで座標取得 |
先回投稿でCANVAS上を動くロケットのアニメーションを作成しましたが、そのプログラムを流用し、CANVASをクリックし座標を取得する様にしてみます。イベントプロパティを使って下の図の通り座標が取得できる様ですので、実際に確認してみました。

確認に使ったプログラムは下記です。ロケットのアニメーションプログラムに行番11,行番57,行番116~129,行番142~148を追加しています。行番142~148は取得した座標を表示するTABLEです。行番11ではこのTABLEの枠線等の設定を行っています。行番57はイベントを監視する「addEventListener()」を設定しています。CANVAS(cvs02)上の “click” イベントを監視し、 イベントが発生した時には、行番116~129の関数 “cvs02_click” を実行します。この関数はクリック位置の座標を取得しテーブル(表)にデータを設定しています。
座標を取得するだけではあまりおもしろくないので、行番127,128で“offset X / Y”の値をそれぞれロケットの中心座標(pos_x,pos_y)に代入しています。この処理によってロケットは即座にクリック位置に移動する様になります。(→デモへのリンク)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>CANVAS レイヤー評価</title>
<style>
.cvs-layer { position: relative; height:370px; }
.cvs-layer canvas { position: absolute; top: 0; left: 0; }
table, td, th { border: 1px #808080 solid; border-collapse : collapse;}
</style>
<script>
const CH_RAD = Math.PI/180;
var pos_x = 0 ;
var pos_y = 0 ;
function draw_test() {
var img01_w = 0 ; var img01_h = 0 ;
const t_img_w = 60 ;
const t_img_h = 60 ;
var r_ang = 0 ;
var lp_cn = 0 ;
var ph_no = 9 ;
var fl_md = 0 ;
//2Dコンテキストオブジェクト生成
var cvs01 = document.getElementById('CANVAS_01');
var ctx01 = cvs01.getContext('2d');
//2Dコンテキストオブジェクト生成
var cvs02 = document.getElementById('CANVAS_02');
var ctx02 = cvs02.getContext('2d');
//画像オブジェクト生成
var img02 = new Image();
img02.src = "space_rocket.png";
//画像オブジェクト生成
var img01 = new Image();
img01.src = "background_01.jpg";
//canvas画像描画(背景)
img01.onload = function(){
img01_w = img01.width ;img01_h = img01.height ;
//背景画像サイズに合わせ、キャンパスサイズ設定
cvs01.width = img01_w ; cvs01.height = img01_h ;
cvs02.width = img01_w ; cvs02.height = img01_h ;
cvs02.addEventListener("click",cvs02_click,false);
//背景画像描画
ctx01.drawImage( img01 , 0 , 0 , img01_w , img01_h );
//開始時 Y 位置
pos_y = img01_h / 2 ;
cvs02_draw_00 () ;
}
//メイン画像描画
function cvs02_draw_00 () {
ctx02.clearRect( 0 , 0 , img01_w , img01_h );
//【参考】傾きを変えずに配置する場合
//ctx02.drawImage( img02 , (img01_w - t_img_w) / 2 , (img01_h - t_img_h) / 2 , t_img_w , t_img_h );
//座標・傾きを変える
ctx02.save();
ctx02.translate( pos_x , pos_y );
ctx02.rotate( (45 + r_ang) * CH_RAD );
ctx02.drawImage( img02 , - t_img_w / 2 , - t_img_h / 2 , t_img_w , t_img_h );
ctx02.restore();
//一定回数繰り返したら方向を変える
lp_cn = lp_cn + 1 ;
if(lp_cn > 70 + 70 * Math.random() ){
lp_cn = 0 ; fl_md = 0 ;
if( ph_no > 3 ){ ph_no = 0 ;
} else { ph_no = ph_no + 1 ; }
}
//次の進む方向を決める
if(fl_md == 0){
fl_md = 1 ;
if(ph_no == 1 || ph_no == 3){
if (Math.random() > 0.5) { r_ang = -45 ;
} else { r_ang = 45 ; }
}else{ r_ang=0 ; }
}
//上下端近くで強制的に向きを変える
if(pos_y >= (img01_h - 0.7 * t_img_h)){ r_ang = -45 ; }
if(0.7 * t_img_h >= pos_y){ r_ang = 45 ; }
//水平移動以外(角度≠0)の時、pos_yを増減する
if( r_ang > 0 ) { pos_y = pos_y + 2 ; }
if( 0 > r_ang ) { pos_y = pos_y - 2 ; }
//横方向移動の、pos_x 増加
pos_x = pos_x + 2 ;
if( pos_x > img01_w + t_img_w ){ pos_x = -1 * t_img_w ; }
requestAnimationFrame(cvs02_draw_00) ;
}
}
function cvs02_click(event){
document.getElementById('scr-x').innerHTML=Math.floor(100*event.screenX)/100 ;
document.getElementById('scr-y').innerHTML=Math.floor(100*event.screenY)/100 ;
document.getElementById('pag-x').innerHTML=Math.floor(100*event.pageX)/100 ;
document.getElementById('pag-y').innerHTML=Math.floor(100*event.pageY)/100 ;
document.getElementById('clt-x').innerHTML=Math.floor(100*event.clientX)/100 ;
document.getElementById('clt-y').innerHTML=Math.floor(100*event.clientY)/100 ;
document.getElementById('oft-x').innerHTML=Math.floor(100*event.offsetX)/100 ;
document.getElementById('oft-y').innerHTML=Math.floor(100*event.offsetY)/100 ;
document.getElementById('rct-x').innerHTML=Math.floor(100*event.target.getBoundingClientRect().left)/100 ;
document.getElementById('rct-y').innerHTML=Math.floor(100*event.target.getBoundingClientRect().top)/100 ;
pos_x = Math.floor(event.offsetX) ;
pos_y = Math.floor(event.offsetY) ;
}
</script>
</head>
<body onLoad="draw_test()">
<H2>CANVAS レイヤー評価</H2>
<div class="cvs-layer">
<canvas id="CANVAS_01"></canvas>
<canvas id="CANVAS_02"></canvas>
</div>
<TABLE>
<TR><TD>screen X / Y</TD><TD id="scr-x">―</TD><TD id="scr-y">―</TD></TR>
<TR><TD>page X / Y</TD><TD id="pag-x">―</TD><TD id="pag-y">―</TD></TR>
<TR><TD>client X / Y</TD><TD id="clt-x">―</TD><TD id="clt-y">―</TD></TR>
<TR><TD>offset X / Y</TD><TD id="oft-x">―</TD><TD id="oft-y">―</TD></TR>
<TR><TD>clientRect X / Y</TD><TD id="rct-x">―</TD><TD id="rct-y">―</TD></TR>
</TABLE>
</body>
</html>
下図はプログラム実行状況です。CANVAS領域下にテーブル(表)が出来て、クリック位置座標が挿入されるのが確認出来ます。
(→デモへのリンク)

| その他のイベント |
いくつか他のイベントを下の表に書いておきます。
| イベント名 | 内 容 |
| touchstart | タッチが開始された瞬間 |
| touchmove | タッチされた後、指を画面上で動かす都度 |
| touchend | タッチされた後、指を画面から話した時 |
| touchcancel | タッチパネルに触れている最中にシステム側から強制的にキャンセルされた時 |
| click | マウスボタンをクリックした時 |
| dblclick | マウスボタンをダブルクリックした時 |
| keydown | キーボードのキーを押した時 |
| keyup | キーボードのキーを離した時 |
| keypress | キーボードのキーを押している時 |
| load | HTML文書の読み込みが完了した時 (画像など全リソース含む) |
| unload | ページを移動する時 |
| DOMContentLoaded | HTML文書の読み込みが完了した時 (画像などのリソース含まない) |
| mouseover | マウスカーソルが乗った時 |
| mouseout | マウスカーソルが外れた時 |
| mousedown | マウスボタンを押している時 |
| mouseup | マウスボタンを離した時 |
| mousemove | マウスカーソルが移動した時 |
| change | フォーム部品の状態が変更された時 |
| submmit | フォームのsubmitボタンを押した時 |
| scroll | 画面がスクロールした時 |
【参考】イベント関連情報 : Event reference
| まとめ |
「addEventListener()」を使ったイベント処理と座標取得について少し考え方の整理が出来ました。いろいろなシーンで応用できる様に少しづつ使って行きたいと思います。