HTML5 Canvas + jQuery でドラッグ&ドロップ
タイトルのとおり、drag&drop を HTML5 Canvasで実装してみた。
こちらで公開しています → HTML5 Canvasでドラッグ&ドロップ
スタートボタンを押して実行してください。
実装してみてわかったことを簡単に解説する。
1. ソースコード
作成したソースコードは以下のとおり。jQuery は ver1.4.2 を使用。
・html および共通の Canvas 描画クラス
dtest.html dtestcom.js
・drag&drop処理(1px 移動するごとに Canvas 更新)
dtest1.js
・drag&drop処理(1/24秒ごとに Canvas 更新)
dtest2.js
2. Canvas 更新方法について
「mousemove イベントが発生するたび更新」 → 「1px 移動するごとに更新」 → 「1/24秒ごとに更新」 の順にCPU負荷が小さくなる。
1) 1px 移動するごとに Canvas 更新
ドラッグ中状態で mousemove イベントが発生した際、現在の座標からX軸方向またはY軸方向に 1px 以上移動した場合のみ更新する。
その部分のソースコードは以下のとおり。
1px を 2px にしたら動きがぎこちなくなった。
2) 1/24秒ごとに Canvas 更新
ドラッグ中状態の場合、イベントに関係無く 1/24秒ごとに Canvas を更新する。
ドラッグしているアイテムの座標は mousemove イベントが発生するたびに更新する。
mousedownイベント発生時に、ドラッグ対象アイテムがあったら window.setInterval() でタイマー実行。
mouseup/mouseleaveイベント発生時などに window.clearInterval() でタイマー停止。
1px 移動するごとに更新する場合に比べて、移動中のCPU負荷が(自分の環境では)半分ぐらい減った。
ソースコードの修正箇所は思ったほど多くは無かった。
今後 drag&drop 以外の処理を追加していくつもりだが、
「スタート時にタイマーを実行し、イベント発生時にフラグのオンオフを行う。Canvas を更新するかはフラグをチェックして判定」
とすればCPU負荷を抑えられる上に複雑にならないだろう。
3. その他
・document上の座標をCanvas上の座標へ変換
イベントオブジェクトから取得できるマウスポインタの座標 (evt.pageX, evt.pageY) はdocument上の座標。
CanvasのDOM要素の左上座標は (offset().left, offset().top) で取得できるので、それを使ってCanvas上の座標へ変換できる。
・クリックした場所にドラッグ対象アイテムがあるかの判定
いわゆる当たり判定。
可能なら Canvas をグリッドでエリア分割すれば楽。
久しぶりだと思ったら、この前 HTML5 Canvas のプログラミングしたのは1ヶ月半前だった。
こちらで公開しています → HTML5 Canvasでドラッグ&ドロップ
スタートボタンを押して実行してください。
実装してみてわかったことを簡単に解説する。
1. ソースコード
作成したソースコードは以下のとおり。jQuery は ver1.4.2 を使用。
・html および共通の Canvas 描画クラス
dtest.html dtestcom.js
・drag&drop処理(1px 移動するごとに Canvas 更新)
dtest1.js
・drag&drop処理(1/24秒ごとに Canvas 更新)
dtest2.js
2. Canvas 更新方法について
「mousemove イベントが発生するたび更新」 → 「1px 移動するごとに更新」 → 「1/24秒ごとに更新」 の順にCPU負荷が小さくなる。
1) 1px 移動するごとに Canvas 更新
ドラッグ中状態で mousemove イベントが発生した際、現在の座標からX軸方向またはY軸方向に 1px 以上移動した場合のみ更新する。
その部分のソースコードは以下のとおり。
// 画面更新するか判定
// cx, cy ポインタのCanvas座標
// dtest1.DRAG.itemAr[dtest1.drag.item].x ドラッグしているアイテムのx座標
// dtest1.DRAG.itemAr[dtest1.drag.item].y ドラッグしているアイテムのy座標
var updSep = 1; // 何px動いたら画面更新するか
if (Math.abs(cx - dtest1.DRAG.itemAr[dtest1.drag.item].x) >= updSep ||
Math.abs(cy - dtest1.DRAG.itemAr[dtest1.drag.item].y) >= updSep) {
// アイテムの座標更新
dtest1.DRAG.itemAr[dtest1.drag.item].x = cx;
dtest1.DRAG.itemAr[dtest1.drag.item].y = cy;
// 画面更新
dtest1.DRAG.draw();
}
わずか1pxだが、この判定処理を入れたことで移動中のCPU負荷が(自分の環境では)1割ぐらい減った。// cx, cy ポインタのCanvas座標
// dtest1.DRAG.itemAr[dtest1.drag.item].x ドラッグしているアイテムのx座標
// dtest1.DRAG.itemAr[dtest1.drag.item].y ドラッグしているアイテムのy座標
var updSep = 1; // 何px動いたら画面更新するか
if (Math.abs(cx - dtest1.DRAG.itemAr[dtest1.drag.item].x) >= updSep ||
Math.abs(cy - dtest1.DRAG.itemAr[dtest1.drag.item].y) >= updSep) {
// アイテムの座標更新
dtest1.DRAG.itemAr[dtest1.drag.item].x = cx;
dtest1.DRAG.itemAr[dtest1.drag.item].y = cy;
// 画面更新
dtest1.DRAG.draw();
}
1px を 2px にしたら動きがぎこちなくなった。
2) 1/24秒ごとに Canvas 更新
ドラッグ中状態の場合、イベントに関係無く 1/24秒ごとに Canvas を更新する。
ドラッグしているアイテムの座標は mousemove イベントが発生するたびに更新する。
mousedownイベント発生時に、ドラッグ対象アイテムがあったら window.setInterval() でタイマー実行。
mouseup/mouseleaveイベント発生時などに window.clearInterval() でタイマー停止。
1px 移動するごとに更新する場合に比べて、移動中のCPU負荷が(自分の環境では)半分ぐらい減った。
ソースコードの修正箇所は思ったほど多くは無かった。
今後 drag&drop 以外の処理を追加していくつもりだが、
「スタート時にタイマーを実行し、イベント発生時にフラグのオンオフを行う。Canvas を更新するかはフラグをチェックして判定」
とすればCPU負荷を抑えられる上に複雑にならないだろう。
3. その他
・document上の座標をCanvas上の座標へ変換
イベントオブジェクトから取得できるマウスポインタの座標 (evt.pageX, evt.pageY) はdocument上の座標。
CanvasのDOM要素の左上座標は (offset().left, offset().top) で取得できるので、それを使ってCanvas上の座標へ変換できる。
// Canvas描画クラス
// document上のCanvas左上座標を求める
// <canvas>タグを認識しないケースを考慮し、同じサイズの<div>タグで囲ってそのDOM要素を取得
// names.con.id.cvdiv は<div>タグのid
var $cvdiv = $('#' + names.con.id.cvdiv);
this.cvpos.x = $cvdiv.offset().left;
this.cvpos.y = $cvdiv.offset().top;
// mousedownイベント時の処理
// ポインタ座標をCanvas座標へ変換
// dtest2.DRAG はCanvas描画クラスのインスタンス
var cx = evt.pageX - dtest2.DRAG.cvpos.x;
var cy = evt.pageY - dtest2.DRAG.cvpos.y;
// document上のCanvas左上座標を求める
// <canvas>タグを認識しないケースを考慮し、同じサイズの<div>タグで囲ってそのDOM要素を取得
// names.con.id.cvdiv は<div>タグのid
var $cvdiv = $('#' + names.con.id.cvdiv);
this.cvpos.x = $cvdiv.offset().left;
this.cvpos.y = $cvdiv.offset().top;
// mousedownイベント時の処理
// ポインタ座標をCanvas座標へ変換
// dtest2.DRAG はCanvas描画クラスのインスタンス
var cx = evt.pageX - dtest2.DRAG.cvpos.x;
var cy = evt.pageY - dtest2.DRAG.cvpos.y;
・クリックした場所にドラッグ対象アイテムがあるかの判定
いわゆる当たり判定。
可能なら Canvas をグリッドでエリア分割すれば楽。
久しぶりだと思ったら、この前 HTML5 Canvas のプログラミングしたのは1ヶ月半前だった。
スポンサーサイト