« スマートフォンでの <span class="sl_ft" style="font-weight:normal">LongDriver</span> の不具合 | トップページ | 非表示⇒表示の実行は同一関数内では無意味・・・たぶん »

2020年3月16日 (月)

touchEvent の奇妙な振る舞い⇒迂回策

フットボールのプレイブック・ソフト LongDriver がスマートフォンで正常に動作していないことは既に書いていますが、いくつか有る不具合のうち1つは改善出来ました。その不具合と対策は以下の通りです。

スマートフォンでの LongDriver

まず、選手を移動する手順(期待される動作)は次の通りです。この手順は、正常に動作した場合のもので、実際は 4. で異常が発生します。

    選手移動手順
  1. 画像の上下に配置している選手のダミーマークをタップ
  2. フィールドに薄い灰色のシート(←仮想マウスパッド)が表示される
  3. そのパッドに指をタッチして動かすとフィールドの選手が移動する
  4. 上記 3. を繰り返す
  5. 画像の左右に有る茶色バーをタップ
  6. 仮想マウスパッドが消える

手順の 3. 4. で発生するイベント touchstart, touchmove, touchend に応じてイベントハンドラー startDrag(), drag(), endDrag() が実行されます。3つのハンドラーとも evt.preventDefault() を実行しています。 startDrag() でイベント touchmove に対するハンドラー drag() が登録され、 endDrag()drag() が解除されます。

function startDrag(evt){
	evt.preventDefault();
	・・・
	pad.addEventListener(touchmove, drag, {passive: false});
}

function drag(evt){
	evt.preventDefault();
	・・・
}

function endDrag(evt){
	evt.preventDefault();
	・・・
	ground.pad.removeEventListener(touchmove, drag, {passive: false});
	・・・
}

上記の選手移動手順を実行していて不思議なのは、 3. を最初に実行する時は問題が発生しないのに、 4. で 3. を繰り返そうとしても drag() が実行されず、選手の移動が出来ないことです。その時、 startDrag()evt.preventDefault()

  • Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.

というエラーが発生します。これは、「スクロールか何かの最中なので evt.preventDefault() 出来ない」ということです・・・スクロール?? そんなことしていないのに? なお、 endDrag()evt.preventDefault() ではこのエラーは発生していません。

選手移動の手順を一通り終了して再度実施すると、同じく 3. は実行出来て 4. でエラーが発生します。これも不思議です。選手移動モードを一旦抜ける(手順の 5. 6.)と、エラーメッセージに有る 「scrolling is in progress」 がキャンセルされるということなのでしょうか? 手順の 6. は hidePad() というハンドラーで実現されています。また、再実行の入り口では手順の 1. 2. で pickup() というハンドラーが実行されます。しかし、これらのハンドラー内で「scrolling is in progress」 のキャンセルに関わりそうな箇所は有りません。何故、手順の再実行が可能なのか不明です。

とにかく、手順を最初から実施すれば、 3. は実行できるので、試しに、デバッガーのコンソールから

ground.pad.setAttribute("display", "none")

ground.pad.setAttribute("display", "inline")

を続けて実行してみました。これらは仮想マウスパッドを非表示および表示するコードです。これを実行すると、直後の1回だけ選手移動(つまり 3.)が出来ました。カラクリは判りませんが、とにかく、仮想マウスパッドを表示しなおせばエラーは発生しないわけです。そこで、そのコードを endDrag() に追加しました(1)。ただし、非表示と表示のコードをただ並べただけではダメで、幾ばくかのディレイが必要です(注意)。数百ミリ秒から試してみて、 10 ミリ秒でもOKなことは確認済みです(最小値かどうかは未確認)。

(注意):訂正有り(非表示⇒表示の実行は同一関数内では無意味・・・たぶん

function endDrag(evt){
	・・・
	if (ground.isTouchPnl){			// (1) 6行追加
		ground.pad.setAttribute("display", "none");
		setTimeout(function(){
			ground.pad.setAttribute("display", "inline");
		}, 10);
	}
}

取り敢えず、これで選手の移動は出来るようになりました。しかし、未だ解決出来ていない不具合は有ります。デバッグはもう少しかかりそうです。

追記:LongDriver にアクセスしただけではキャッシュが残っていて、デバッグの効果が反映されないかも知れません。 LongDriver のキャッシュをクリアーしてからアクセスする必要が有ります。

« スマートフォンでの <span class="sl_ft" style="font-weight:normal">LongDriver</span> の不具合 | トップページ | 非表示⇒表示の実行は同一関数内では無意味・・・たぶん »

フットボールのプレイ図ソフト」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

« スマートフォンでの <span class="sl_ft" style="font-weight:normal">LongDriver</span> の不具合 | トップページ | 非表示⇒表示の実行は同一関数内では無意味・・・たぶん »