iPod & iPad & iPhoneで、クリックイベントを発火させて、それを使えるようにする!
- touchstartイベントが発生したときの座標を覚えておく。
- touchmoveイベントで、軌跡を記録。
- touchendイベントで、移動距離を計算。
- 一定の範囲内なら、clickとみなす。
その1。
<!DOCTYPE html> <html lang="ja"> <head> <title></title> <meta charset="utf-8"> <meta name="viewport" content="width=640"> <style> </style> </head> <body> <h1>iPod Touch & iPad Click Test</h1> <p> click イベントが使えない。しかも touchendイベントの時に座標を得られないそうだ。 <p> なので、touchmoveイベントも使いながら座標を記憶する <script> (function () { function Click (node, cbFunc, cbObject, arg) { this.node = node; this.cbFunc = cbFunc; this.range = 10; this.cbObject = cbObject; this.arg = arg; this.event = null; this.startPoint = { 'x' : null, 'y' : null }; this.currentPoint = { 'x' : null, 'y' : null }; } function addEvent () { this.node.addEventListener ('touchstart', this, false); this.node.addEventListener ('touchmove', this, false); this.node.addEventListener ('touchend', this, false); } function handler (event) { var touch = event.touches; if (1 < touch.length) return; if((touch = touch[0])) { switch (event.type) { case 'touchstart' : this.currentPoint.x = this.startPoint.x = touch.pageX; this.currentPoint.y = this.startPoint.y = touch.pageY; this.event = event; break; case 'touchmove' : this.currentPoint.x = touch.pageX; this.currentPoint.y = touch.pageY; break; case 'touchend' : if (this.range > (Math.abs (this.currentPoint.x - this.startPoint.x))) if (this.range > (Math.abs (this.currentPoint.y - this.startPoint.y))) { this.cbFunc.apply (this.cbObject, [this.event].concat (this.arg)); } break; } } } //_____________ function createHandler (node, cbFunc, cbObject /*, thisp*/) { var obj, arg; if (2 > arguments.length) return null; if (1 !== node.nodeType && 9 !== node.nodeType) return null; if ('function' !== typeof cbFunc) if (('object' !== typeof cbFunc) && ! ('handleEvent' in cbFunc)) return null; arg = Array.prototype.slice.call (arguments, 3); obj = new Click (node, cbFunc, cbObject, arg); obj.addEvent (); return obj; } //_____________ Click.prototype.addEvent = addEvent; Click.prototype.handleEvent = handler; this.addClickHandler = createHandler; })(); var func = function (a, b ,c) { alert (["Click", this, a, b, c]); }; var clickEvent = addClickHandler (document, func, 1, 2 , 3); </script>
その2.
this.node を不要に。(私的所有物なら、「なにかのために取っておこう」と思うのだが、ここは、ばっさり)
(function () { function Click (cbFunc, cbObject, arg) { this.cbFunc = cbFunc; this.range = 10; this.cbObject = cbObject; this.arg = arg; this.event = null; this.startPoint = { 'x' : null, 'y' : null }; this.currentPoint = { 'x' : null, 'y' : null }; } function handler (event) { var touch = event.touches; if (1 < touch.length) return; if((touch = touch[0])) { switch (event.type) { case 'touchstart' : this.currentPoint.x = this.startPoint.x = touch.pageX; this.currentPoint.y = this.startPoint.y = touch.pageY; this.event = event; break; case 'touchmove' : this.currentPoint.x = touch.pageX; this.currentPoint.y = touch.pageY; break; case 'touchend' : if (this.range > (Math.abs (this.currentPoint.x - this.startPoint.x))) if (this.range > (Math.abs (this.currentPoint.y - this.startPoint.y))) { this.cbFunc.apply (this.cbObject, [this.event].concat (this.arg)); } break; } } } //_____________ function createHandler (node, cbFunc, cbObject /*, thisp*/) { var obj, arg; if (2 > arguments.length) return null; if (1 !== node.nodeType && 9 !== node.nodeType) return null; if ('function' !== typeof cbFunc) if (('object' !== typeof cbFunc) && ! ('handleEvent' in cbFunc)) return null; arg = Array.prototype.slice.call (arguments, 3); obj = new Click (cbFunc, cbObject, arg); node.addEventListener ('touchstart', obj, false); node.addEventListener ('touchmove', obj, false); node.addEventListener ('touchend', obj, false); return obj; } //_____________ Click.prototype.handleEvent = handler; this.addClickHandler = createHandler; })();
その3。
タッチの数が1の時だけ実行するようにしていたが、touchend イベントが実行されているときは、タッチ数が0。後で直さなきゃ〜!
<!DOCTYPE html> <title></title> <meta name="viewport" content="width=640"> <style> p.focus { border: 1px red solid; } </style> <body> <h1>iPod Touch & iPad Click Test</h1> <p class="focus"> click イベントが使えない。しかも touchendイベントの時に座標を得られないそうだ。 <p id="test"> なので、touchmoveイベントも使いながら座標を記憶する <p> click イベントが使えない。しかも touchendイベントの時に座標を得られないそうだ。 <p id="test"> なので、touchmoveイベントも使いながら座標を記憶する <p> click イベントが使えない。しかも touchendイベントの時に座標を得られないそうだ。 <p id="test"> なので、touchmoveイベントも使いながら座標を記憶する <input type="text" id="tt"> <script> document.addEventListener ('click', function (e) { var n = e.target; n.className = n.className ? '': 'focus'; }, false); (function () { function Emulator () { this.range = 10; this.startPoint = { 'x' : 0, 'y' : 0 }; this.currentPoint = { 'x' : 0, 'y' : 0 }; } function fire (event) { var e = event.target; var doc = e.ownerDocument; var evt = doc.createEvent ('MouseEvents'); if (3 === e.nodeType) e = e.parentNode; evt.initMouseEvent( 'click', // イベント名 true, // バブリングするか true, // デフォルトアクションが取り消し可能か doc.defaultView, // イベントが発生したビュー 1, // クリック回数 this.currentPoint.x, // スクリーン内のマウスの X 座標 this.currentPoint.y, // スクリーン内のマウスの Y 座標 this.currentPoint.x, // ブラウザ表示域内のマウスの X 座標 this.currentPoint.y, // ブラウザ表示域内のマウスの Y 座標 false, // Ctrl キーが押されているか false, // Alt キーが押されているか false, // Shift キーが押されているか false, // Meta キーが押されているか 0, // どのボタンが押されているか(左から順に 0、1、2) doc.body // 関連するノード(何でも良い) ); e.dispatchEvent(evt); } function handler (event) { var touch = event.touches; switch (event.type) { case 'touchstart' : if (1 < touch.length) return; if ((touch = touch[0])) { // スタートとカーレント位置を同期させる this.currentPoint.x = this.startPoint.x = touch.pageX; this.currentPoint.y = this.startPoint.y = touch.pageY; } break; case 'touchmove' : if ((touch = touch[0])) { // カーレント位置を記憶 this.currentPoint.x = touch.pageX; this.currentPoint.y = touch.pageY; } break; case 'touchend' : if (this.range > (Math.abs (this.currentPoint.x - this.startPoint.x))) if (this.range > (Math.abs (this.currentPoint.y - this.startPoint.y))) fire.call (this, event); break; } } // クリック・エミュレータ初期化 function emulator_init (view) { var doc = view ? view.document: document; var emu = new Emulator; doc.addEventListener ('touchstart', emu, false); doc.addEventListener ('touchmove', emu, false); doc.addEventListener ('touchend', emu, false); return emu; } Emulator.prototype.handleEvent = handler; Emulator.init = emulator_init; this.ClickEmulator = Emulator; })(); ClickEmulator.init (this); </script>