Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

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

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige

Hier ansehen

1 von 49 Anzeige
Anzeige

Weitere Verwandte Inhalte

Aktuellste (20)

Anzeige

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

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

×