SlideShare a Scribd company logo
1 of 49
Download to read offline
Text
マウスホイールイベント処理
マニアックス
中野雅之
• 肩書き
• 正式: Mozilla Japan 国際化担当マネージャ
• 半公式: Mozilla Japan ジョギング部大阪支部長
• 非公式: Mozilla Japan 大阪支部長
• 大阪の自宅で、自宅警備しながら仕事してます
中野雅之
• 色んなアカウント
• メールアドレス: masayuki@d-toybox.com
• Skype: masayuki-nakano
• Twitter: @d_toybox
• Facebook: masayuki.nakano.560
• Blog: 「もずはっく日記」で検索
アジェンダ
• 各プラットフォームのネイティブイベント
• レガシーイベント
• MouseScrollEvent
• MouseWheelEvent
• WheelEvent
• WheelEventとレガシーイベントの関係
• デフォルトアクションの考え方
各プラットフォームの
ネイティブイベント
各プラットフォームのネイティブイベント
• Windows
• WM_MOUESEWHEEL (Win 98以降)
• 垂直方向へのホイール操作に対するイベント
• マウスホイールの回転量が伝達される
• 1ノッチあたり120
• Vista以降では120未満のデルタ値でも発生する (高解像度スクロ
ール)
• ページ単位でのスクロールにも設定可能
• WM_MOUSEHWHEEL (Win Vista以降)
• 水平方向へのホイール操作に対するイベント
• 詳細はWM_MOUSEWHEELと同様
各プラットフォームのネイティブイベント
• Mac
• -deltaX、-deltaY、-deltaZ
• ピクセルスクロールをサポートしていないデバイスで利用
• スクロールする行数を示すと思われる(ドキュメントに明記されてい
ない)
• deltaZを利用するデバイスは無い?
• -scrollingDeltaX、-scrollingDeltaY
• ピクセルスクロールをサポートしているデバイスで利用
• 連続スクロールをサポートするデバイスか否か、という概念がある
• OSレベルで操作量・頻度に応じて、加速が行われる
• システム設定でスクロール速度はカスタマイズ可能
各プラットフォームのネイティブイベント
• Linux
• GdkEventScrollというイベントが発生し、スクロール方向のみ
が分かる
• システム設定でもスクロール量は設定できないので、アプリの
解釈によってスクロール量が決まる
MouseScrollEvent
MouseScrollEvent
• Firefox独自イベント
• Firefoxでは、window.MouseScrollEventは、undefined
にはならない
• DOMMouseScrollと、MozMousePixelScrollの二つのイ
ベントが存在する
• 関係性や動作が非常に複雑
MouseScrollEvent
• 属性
• detail
• スクロール量を表す
• 正なら、下、もしくは右方向
• 負なら、上、もしくは左方向
• axis
• HORIZONTAL_AXIS (1) なら水平方向
• VERTICAL_AXIS (2) なら垂直方向
MouseScrollEvent
• DOMMouseScroll
• detail値は、スクロールする行数
• detail値がSCROLL_PAGE_DOWN (32768)か、
SCROLL_PAGE_UP (-32768)なら、1ページ、スクロール
(Windowsのみ)
• MozMousePixelScroll
• detail値は、スクロールするピクセル数
MouseScrollEvent
• DOMMouseScrollとMozMousePixelScrollの関係
• MozMousePixelScrollのスクロール量がtargetの行高
で、1行分以上累積した場合にのみ、
DOMMouseScrollイベントも発生する
• 両方発生する場合の発生順序は、 DOMMouseScroll
が先で、 MozMousePixelScrollが後
MouseScrollEvent
• DOMMouseScrollとMozMousePixelScrollの関係
• MozMousePixelScrollのみが発生することがあること
に注意
• DOMMouseScrollイベントだけでpreventDefault()を呼
び出してもスクロールは完全に抑制できない
• Google Mapsでも実際に、これが原因のバグがある
• Bug 681200 - Mouse wheel on google maps
zooms map and scrolls page
MouseWheelEvent
MouseWheelEvent
• IE発祥のイベント。Firefox以外のメジャーブラウザは実
装している
• ただし、実装方法は、ブラウザ間でバラバラ
• IEでのみwindow.MouseWheelEventがundefinedではな
い (Chrome 27、Safari 6、Opera12.12では、サポートし
ているにも関わらず、undefined)
• mousewheelイベントのみが存在する
MouseWheelEvent
• 属性
• wheelDelta
• ホイールの回転量を表す
• 正なら、奥方向、負なら、手前方向へホイールが回転
したことを表す
• IEでは垂直方向へのホイール操作でしか発生しない
• 値については後ほど解説
MouseWheelEvent
• 属性
• detail値
• Opera以外では常にゼロ
• Operaではスクロールする行数を示すと思われる値
• 下、もしくは右への操作なら、正の値
• 上、もしくは左への操作なら、負の値
MouseWheelEvent
• 属性
• wheelDeltaX
• 水平方向へのホイールの回転量を表す
• Chrome、Safari、Operaでのみサポート
• IE非サポート
• 値の内容はwheelDeltaと同様
• 右への操作なら、負の値、左への操作なら正の値
MouseWheelEvent
• 属性
• wheelDeltaY
• 垂直方向へのホイールの回転量を表す
• Chrome、Safari、Operaでのみサポート
• IE非サポート
• 値の内容はwheelDeltaと同様
• 下への操作なら、負の値、上への操作なら正の値
MouseWheelEvent
• wheelDelta*の値の闇
• IEでは、ネイティブイベントのWM_MOUSEWHEEL、
WM_MOUSEHWHEELのデルタ値がそのまま設定されるため、
常に、ホイールの回転量を表す
• 高解像度スクロールがサポートされていないデバイス
であれば、1ノッチあたり、120になる
MouseWheelEvent
• wheelDelta*の値の闇
• Windows版Chromeでは、IE同様、ネイティブイベント
のWM_MOUSEWHEEL、WM_MOUSEHWHEELのデルタ値がその
まま設定されるため、常に、ホイールの回転量を表す
• 高解像度スクロールがサポートされていないデバイス
であれば、1ノッチあたり、120になる
MouseWheelEvent
• wheelDelta*の値の闇
• Mac版Chromeでは、連続スクロールがサポートされて
いないデバイスの場合、加速を考慮しない値、つまり、
純粋な操作量が利用される。手元のマウスでは1ノッチ
で120
• 連続スクロールがサポートされているデバイスの場合、
加速を考慮した値を使用している。おそらく、Safariと同
じ結果になる
MouseWheelEvent
• wheelDelta*の値の闇
• Safariでは、連続スクロールがサポートされているデバ
イスでも、そうではないデバイスでも関係なく、加速を考
慮した値を使用している
• 連続スクロールがサポートされていないデバイスの場
合、Mac版Chromeとは異なる値になる
MouseWheelEvent
• wheelDelta*の値の闇
• Mac版Operaでは、連続スクロールがサポートされてい
るデバイスでも、そうではないデバイスでも関係なく、加
速を考慮した値を使用している
• スクロール量(detail値)に対して、-40倍の値が用いら
れているため、多くの場合、同じ操作で、Chromeや
Safariよりも格段に大きな数字になる
MouseWheelEvent
• wheelDelta*の値の闇
• Mac版のブラウザでは、加速を考慮した場合には、
Windows版や、Linux版の同じブラウザとも互換性がな
くなる
• その理由は簡単で、デバイスの操作量を示す物理的な
デルタ値のはずが、Macでのみ、論理的なスクロール
量に応じて算出した値を用いているため
MouseWheelEvent
• wheelDelta*の値の闇
• Linux版Chromeでは、1ネイティブイベントあたり、120
がセットされるため、Windows版との互換性が高い
• Linux版Operaでは、1ネイティブイベントあたり、80が
セットされる
レガシーイベントまとめ
• Firefoxのみが独自イベントを実装しているが、理解すれ
ば一番実用的(ただし、複雑で好ましいものではない)
• IEでは横スクロールに対応できない
• Chrome、Safari、Operaでは互換性がなさ過ぎる上に、
Chromeの動作に関しては、ブラウザの名前から処理を
切り分けることも不可能にしている
• 要するに、Firefox以外では使い物にならない
WheelEvent
WheelEvent
• W3CのDOM Level 3 Eventsで標準化されている
• IE 9発祥のイベントで、Firefoxも、17以降でサポート
• Safari、Chromeはオブジェクトのみサポートしているた
め、window.WheelEventは、IE、Firefox、Safari、
Chromeでundefinedとならない
• wheelイベントのみが存在し、斜め方向のスクロールも
ひとつのイベントで表現できるようになっている
WheelEvent
• 属性
• deltaX、deltaY
• X軸、Y軸方向へのスクロール量をdouble値で示す
• 正なら、右、もしくは下方向
• 負なら、左、もしくは上方向
• Firefoxでは、Macで加速が行われている場合、その値
が反映される
WheelEvent
• 属性
• deltaZ
• Z軸方向へのスクロール量をdouble値で示す
• Macのネイティブイベントに存在する概念なので存在
すると思われる
• FirefoxではMac版でも常にゼロとなる(正負をどうす
れば良いのか判断できないため)
• 他のOSではそもそもこの概念はない
WheelEvent
• 属性
• deltaMode
• deltaX、deltaY、deltaZの値の単位を表す
• DOM_DELTA_PIXEL (0)の場合、ピクセル数
• DOM_DELTA_LINE (1)の場合、行数
• DOM_DELTA_PAGE (2)の場合、ページ数
• delta*がdouble値のため、0.5行のスクロールや、0.5
ページのスクロール、といった表現が可能
WheelEvent
• IE9
• deltaX、deltaY、deltaZはdouble値ではなく、整数値
• IE9、IE10
• deltaMode値はDOM_DELTA_PIXEL
• 行単位のスクロールの場合、1行、もしくは1文字あたり、
固定値を乗算した値(参考: Y方向時: 32px (IE10)、
41px (IE9)、おそらく環境・設定依存)
• ページ単位のスクロールの場合、そのページの高さ(≠
実際にスクロールされる要素の高さ)
WheelEvent
• Firefox
• Windows版では、deltaMode値は、DOM_DELTA_LINEか、
DOM_DELTA_PAGE (システム設定依存)
• Linux版では、deltaMode値は常に、DOM_DELTA_LINE
• Mac版では、deltaMode値は、DOM_DELTA_LINEか、
DOM_DELTA_PIXEL (操作したデバイスがピクセル単
位のスクロールをサポートしているか否かに依存)
• 各delta値は設定で変更できるため、ゲームの入力のよ
うな用途では利用できない
WheelEventと
レガシーイベントの関係
WheelEventとレガシーイベントの関係
• IE、Firefox共通
• "wheel"イベントが発生した後に、レガシーイベントが発
生する
• "wheel"イベント、レガシーイベントのどちらの
preventDefault()でも、デフォルトアクションをキャン
セルできる
• "wheel"イベントで、preventDefault()を呼び出すと、
レガシーイベントは発生しない
WheelEventとレガシーイベントの関係
• Firefox
• "wheel"イベントの情報と、イベントのターゲットの行高
や、targetに一番近い、スクロール可能な要素の幅・高
さから、レガシーイベントが生成される
WheelEventとレガシーイベントの関係
• まとめると、WheelEventをサポートしているブラウザであ
れば、"wheel"イベントのみを処理し、それ以外のブラウ
ザでは、"mousewheel"イベントを処理すれば良い
• しかし、Chrome、Safariでは、window.WheelEventが
undefinedを返さないので正しい判定が不可能になって
いる
WheelEventとレガシーイベントの関係
• イベント処理後に必ず、preventDefault()を呼び出す
のであれば、全てのイベントにリスナを設置することで解
決する
• 例:
foo.addEventListener("wheel", wheelHandler, false);
foo.addEventListener("mousewheel"
mousewheelHandler, false);
WheelEventとレガシーイベントの関係
• イベント処理後に、preventDefault()を呼び出さないの
であれば、悩ましい。
• "onwheel" in document.bodyはFirefoxではtrueにな
るが、IEではfalse
• window.MouseWheelEventはIE 8以前、Safari、Chrome、
Operaはundefinedを返すので、IE 9以降かどうかの判
定に使えるものの、Safari、Chromeが実装を改善すると、
破綻するので危険
デフォルトアクションの考え方
デフォルトアクションの考え方
• preventDefault()を呼び出さない場合に、ブラウザによ
って実行されるのがデフォルトアクション
• モディファイアキー無しであれば、スクロールが一般的
• Windowsであれば、Ctrlキーを押している場合、スクロー
ルではなく、ズームになるのが一般的
• つまり、"wheel"イベントや、レガシーホイールイベント
は、スクロールが発生することを予告するイベントでは
ない
デフォルトアクションの考え方
• Firefoxでは、マウスホイールの操作にトランザク
ションの概念があるため、targetに一番近い、スク
ロール可能な祖先要素がスクロールされるとは限ら
ない(Mouse wheel transaction)
• ページ全体にスクロール中に、他のスクロール可能な
要素がマウスカーソルの下に移動してきても、ページ
全体をスクロール対象として考える(タイムアウトあり)
• DOMイベントのtargetは、これに関係なく、常に、カー
ソルの下にある要素になる
デフォルトアクションの考え方
• つまり、デフォルトアクションがスクロールの場合であっ
ても、"wheel"イベントは、実際のデフォルトアクション
の内容と一致するとは限らない
デフォルトアクションの考え方
• これらのことから言えるのは、"wheel"イベントやレガシ
ーイベントを利用して、独自のスクロール可能な要素を
作る場合には細心の注意が必要
• 本当に必要なことか?
• アクセシビリティへの配慮は十分か?
• 全てのプラットフォームの全てのブラウザの、全ての
現役のバージョンでテストする覚悟(予算)はあるか?
• 万が一、問題が報告された場合に対応する覚悟(余
裕)はあるか?
まとめ
•できれば、面倒極まりないので、関わらない
•やるなら、WheelEventをメインに、がんばる
•WebKitとBlink陣営に、WheelEventを実装する
ようにみんなで声をあげよう!
Text
Q&A?

More Related Content

What's hot

.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理KageShiron
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型信之 岩永
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門uchan_nos
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミングPreferred Networks
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する増田 亨
 
人生で大事なことは XP白本と参考文献に教わった in ESM
人生で大事なことは XP白本と参考文献に教わった in ESM人生で大事なことは XP白本と参考文献に教わった in ESM
人生で大事なことは XP白本と参考文献に教わった in ESMTakeshi Kakeda
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介torisoup
 
UniRxでMV(R)Pパターン をやってみた
UniRxでMV(R)PパターンをやってみたUniRxでMV(R)Pパターンをやってみた
UniRxでMV(R)Pパターン をやってみたtorisoup
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説murachue
 
WebGL Performance Tuning Tips
WebGL Performance Tuning TipsWebGL Performance Tuning Tips
WebGL Performance Tuning TipsYukio Andoh
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)mosa siru
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣Masahiro Nishimi
 
プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造Takuya Akiba
 
.NETで動くチケット管理ツール「プリザンター」
.NETで動くチケット管理ツール「プリザンター」.NETで動くチケット管理ツール「プリザンター」
.NETで動くチケット管理ツール「プリザンター」Taiji Uchida
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
UniTask入門
UniTask入門UniTask入門
UniTask入門torisoup
 
型安全性入門
型安全性入門型安全性入門
型安全性入門Akinori Abe
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方増田 亨
 

What's hot (20)

.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理.NET Core 3.0時代のメモリ管理
.NET Core 3.0時代のメモリ管理
 
C# 8.0 null許容参照型
C# 8.0 null許容参照型C# 8.0 null許容参照型
C# 8.0 null許容参照型
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
C++でできる!OS自作入門
C++でできる!OS自作入門C++でできる!OS自作入門
C++でできる!OS自作入門
 
できる!並列・並行プログラミング
できる!並列・並行プログラミングできる!並列・並行プログラミング
できる!並列・並行プログラミング
 
ドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解するドメイン駆動設計 基本を理解する
ドメイン駆動設計 基本を理解する
 
人生で大事なことは XP白本と参考文献に教わった in ESM
人生で大事なことは XP白本と参考文献に教わった in ESM人生で大事なことは XP白本と参考文献に教わった in ESM
人生で大事なことは XP白本と参考文献に教わった in ESM
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
UniRxでMV(R)Pパターン をやってみた
UniRxでMV(R)PパターンをやってみたUniRxでMV(R)Pパターンをやってみた
UniRxでMV(R)Pパターン をやってみた
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
WebGL Performance Tuning Tips
WebGL Performance Tuning TipsWebGL Performance Tuning Tips
WebGL Performance Tuning Tips
 
開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)開発速度が速い #とは(LayerX社内資料)
開発速度が速い #とは(LayerX社内資料)
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣デキるプログラマだけが知っているコードレビュー7つの秘訣
デキるプログラマだけが知っているコードレビュー7つの秘訣
 
プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造
 
.NETで動くチケット管理ツール「プリザンター」
.NETで動くチケット管理ツール「プリザンター」.NETで動くチケット管理ツール「プリザンター」
.NETで動くチケット管理ツール「プリザンター」
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
UniTask入門
UniTask入門UniTask入門
UniTask入門
 
型安全性入門
型安全性入門型安全性入門
型安全性入門
 
ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方ドメインオブジェクトの見つけ方・作り方・育て方
ドメインオブジェクトの見つけ方・作り方・育て方
 

マウスホイールイベント処理マニアックス