SlideShare a Scribd company logo
マウスホイールイベント処理マニアックス
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

PPTX
SSH超入門
PDF
最新の HPC 技術を生かした AI・ビッグデータインフラの東工大 TSUBAME3.0 及び産総研 ABCI
PDF
ZOZOTOWNのアーキテクトという役割を紹介します
PPTX
Azure サービスを活用して作るフルマネージドな全文検索アプリケーション
PDF
AWS Black Belt Techシリーズ Amazon WorkDocs / Amazon WorkMail
PDF
アドテク×Scala×パフォーマンスチューニング
PDF
AWS Black Belt Techシリーズ Amazon Kinesis
PDF
Aurora
SSH超入門
最新の HPC 技術を生かした AI・ビッグデータインフラの東工大 TSUBAME3.0 及び産総研 ABCI
ZOZOTOWNのアーキテクトという役割を紹介します
Azure サービスを活用して作るフルマネージドな全文検索アプリケーション
AWS Black Belt Techシリーズ Amazon WorkDocs / Amazon WorkMail
アドテク×Scala×パフォーマンスチューニング
AWS Black Belt Techシリーズ Amazon Kinesis
Aurora

What's hot (20)

PDF
ひとりドキュメント担当の仕事を楽しむ
PDF
機械学習アーキテクチャ・デザインパターン
PDF
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
PDF
WebSocketのキホン
PDF
君はyarn.lockをコミットしているか?
PDF
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
PDF
SSII2021 [OS3-03] 画像と点群を用いた、森林という広域空間のゾーニングと施業管理
PDF
IAM Roles Anywhereのない世界とある世界(2022年のAWSアップデートを振り返ろう ~Season 4~ 発表資料)
PDF
Akkaで分散システム入門
PPTX
これがCassandra
PDF
VPC Reachability Analyzer 使って人生が変わった話
PDF
AWSとオンプレミスを繋ぐときに知っておきたいルーティングの基礎知識(CCSI監修!)
PPTX
サーバーレスで ガチ本番運用までやってるお話し
PDF
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
PDF
ドキュメントの継続的改善―Sphinxを使いながら
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
PDF
ZabbixによるAWS監視のコツ
PDF
WindowsではじめるROSプログラミング
PDF
そんなトランザクションマネージャで大丈夫か?
PDF
PGCon.jp 2014 jsonb-datatype-20141205
ひとりドキュメント担当の仕事を楽しむ
機械学習アーキテクチャ・デザインパターン
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
WebSocketのキホン
君はyarn.lockをコミットしているか?
20210127 今日から始めるイベントドリブンアーキテクチャ AWS Expert Online #13
SSII2021 [OS3-03] 画像と点群を用いた、森林という広域空間のゾーニングと施業管理
IAM Roles Anywhereのない世界とある世界(2022年のAWSアップデートを振り返ろう ~Season 4~ 発表資料)
Akkaで分散システム入門
これがCassandra
VPC Reachability Analyzer 使って人生が変わった話
AWSとオンプレミスを繋ぐときに知っておきたいルーティングの基礎知識(CCSI監修!)
サーバーレスで ガチ本番運用までやってるお話し
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
ドキュメントの継続的改善―Sphinxを使いながら
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
ZabbixによるAWS監視のコツ
WindowsではじめるROSプログラミング
そんなトランザクションマネージャで大丈夫か?
PGCon.jp 2014 jsonb-datatype-20141205
Ad

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