1 | /**
|
2 | * Copyright (c) 2015, Facebook, Inc.
|
3 | * All rights reserved.
|
4 | *
|
5 | * This source code is licensed under the BSD-style license found in the
|
6 | * LICENSE file in the root directory of this source tree. An additional grant
|
7 | * of patent rights can be found in the PATENTS file in the same directory.
|
8 | *
|
9 | * @providesModule normalizeWheel
|
10 | * @typechecks
|
11 | */
|
12 |
|
13 | ;
|
14 |
|
15 | var UserAgent_DEPRECATED = require('./UserAgent_DEPRECATED');
|
16 |
|
17 | var isEventSupported = require('./isEventSupported');
|
18 |
|
19 |
|
20 | // Reasonable defaults
|
21 | var PIXEL_STEP = 10;
|
22 | var LINE_HEIGHT = 40;
|
23 | var PAGE_HEIGHT = 800;
|
24 |
|
25 | /**
|
26 | * Mouse wheel (and 2-finger trackpad) support on the web sucks. It is
|
27 | * complicated, thus this doc is long and (hopefully) detailed enough to answer
|
28 | * your questions.
|
29 | *
|
30 | * If you need to react to the mouse wheel in a predictable way, this code is
|
31 | * like your bestest friend. * hugs *
|
32 | *
|
33 | * As of today, there are 4 DOM event types you can listen to:
|
34 | *
|
35 | * 'wheel' -- Chrome(31+), FF(17+), IE(9+)
|
36 | * 'mousewheel' -- Chrome, IE(6+), Opera, Safari
|
37 | * 'MozMousePixelScroll' -- FF(3.5 only!) (2010-2013) -- don't bother!
|
38 | * 'DOMMouseScroll' -- FF(0.9.7+) since 2003
|
39 | *
|
40 | * So what to do? The is the best:
|
41 | *
|
42 | * normalizeWheel.getEventType();
|
43 | *
|
44 | * In your event callback, use this code to get sane interpretation of the
|
45 | * deltas. This code will return an object with properties:
|
46 | *
|
47 | * spinX -- normalized spin speed (use for zoom) - x plane
|
48 | * spinY -- " - y plane
|
49 | * pixelX -- normalized distance (to pixels) - x plane
|
50 | * pixelY -- " - y plane
|
51 | *
|
52 | * Wheel values are provided by the browser assuming you are using the wheel to
|
53 | * scroll a web page by a number of lines or pixels (or pages). Values can vary
|
54 | * significantly on different platforms and browsers, forgetting that you can
|
55 | * scroll at different speeds. Some devices (like trackpads) emit more events
|
56 | * at smaller increments with fine granularity, and some emit massive jumps with
|
57 | * linear speed or acceleration.
|
58 | *
|
59 | * This code does its best to normalize the deltas for you:
|
60 | *
|
61 | * - spin is trying to normalize how far the wheel was spun (or trackpad
|
62 | * dragged). This is super useful for zoom support where you want to
|
63 | * throw away the chunky scroll steps on the PC and make those equal to
|
64 | * the slow and smooth tiny steps on the Mac. Key data: This code tries to
|
65 | * resolve a single slow step on a wheel to 1.
|
66 | *
|
67 | * - pixel is normalizing the desired scroll delta in pixel units. You'll
|
68 | * get the crazy differences between browsers, but at least it'll be in
|
69 | * pixels!
|
70 | *
|
71 | * - positive value indicates scrolling DOWN/RIGHT, negative UP/LEFT. This
|
72 | * should translate to positive value zooming IN, negative zooming OUT.
|
73 | * This matches the newer 'wheel' event.
|
74 | *
|
75 | * Why are there spinX, spinY (or pixels)?
|
76 | *
|
77 | * - spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn
|
78 | * with a mouse. It results in side-scrolling in the browser by default.
|
79 | *
|
80 | * - spinY is what you expect -- it's the classic axis of a mouse wheel.
|
81 | *
|
82 | * - I dropped spinZ/pixelZ. It is supported by the DOM 3 'wheel' event and
|
83 | * probably is by browsers in conjunction with fancy 3D controllers .. but
|
84 | * you know.
|
85 | *
|
86 | * Implementation info:
|
87 | *
|
88 | * Examples of 'wheel' event if you scroll slowly (down) by one step with an
|
89 | * average mouse:
|
90 | *
|
91 | * OS X + Chrome (mouse) - 4 pixel delta (wheelDelta -120)
|
92 | * OS X + Safari (mouse) - N/A pixel delta (wheelDelta -12)
|
93 | * OS X + Firefox (mouse) - 0.1 line delta (wheelDelta N/A)
|
94 | * Win8 + Chrome (mouse) - 100 pixel delta (wheelDelta -120)
|
95 | * Win8 + Firefox (mouse) - 3 line delta (wheelDelta -120)
|
96 | *
|
97 | * On the trackpad:
|
98 | *
|
99 | * OS X + Chrome (trackpad) - 2 pixel delta (wheelDelta -6)
|
100 | * OS X + Firefox (trackpad) - 1 pixel delta (wheelDelta N/A)
|
101 | *
|
102 | * On other/older browsers.. it's more complicated as there can be multiple and
|
103 | * also missing delta values.
|
104 | *
|
105 | * The 'wheel' event is more standard:
|
106 | *
|
107 | * http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
|
108 | *
|
109 | * The basics is that it includes a unit, deltaMode (pixels, lines, pages), and
|
110 | * deltaX, deltaY and deltaZ. Some browsers provide other values to maintain
|
111 | * backward compatibility with older events. Those other values help us
|
112 | * better normalize spin speed. Example of what the browsers provide:
|
113 | *
|
114 | * | event.wheelDelta | event.detail
|
115 | * ------------------+------------------+--------------
|
116 | * Safari v5/OS X | -120 | 0
|
117 | * Safari v5/Win7 | -120 | 0
|
118 | * Chrome v17/OS X | -120 | 0
|
119 | * Chrome v17/Win7 | -120 | 0
|
120 | * IE9/Win7 | -120 | undefined
|
121 | * Firefox v4/OS X | undefined | 1
|
122 | * Firefox v4/Win7 | undefined | 3
|
123 | *
|
124 | */
|
125 | function normalizeWheel(/*object*/ event) /*object*/ {
|
126 | var sX = 0, sY = 0, // spinX, spinY
|
127 | pX = 0, pY = 0; // pixelX, pixelY
|
128 |
|
129 | // Legacy
|
130 | if ('detail' in event) { sY = event.detail; }
|
131 | if ('wheelDelta' in event) { sY = -event.wheelDelta / 120; }
|
132 | if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120; }
|
133 | if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120; }
|
134 |
|
135 | // side scrolling on FF with DOMMouseScroll
|
136 | if ( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
|
137 | sX = sY;
|
138 | sY = 0;
|
139 | }
|
140 |
|
141 | pX = sX * PIXEL_STEP;
|
142 | pY = sY * PIXEL_STEP;
|
143 |
|
144 | if ('deltaY' in event) { pY = event.deltaY; }
|
145 | if ('deltaX' in event) { pX = event.deltaX; }
|
146 |
|
147 | if ((pX || pY) && event.deltaMode) {
|
148 | if (event.deltaMode == 1) { // delta in LINE units
|
149 | pX *= LINE_HEIGHT;
|
150 | pY *= LINE_HEIGHT;
|
151 | } else { // delta in PAGE units
|
152 | pX *= PAGE_HEIGHT;
|
153 | pY *= PAGE_HEIGHT;
|
154 | }
|
155 | }
|
156 |
|
157 | // Fall-back if spin cannot be determined
|
158 | if (pX && !sX) { sX = (pX < 1) ? -1 : 1; }
|
159 | if (pY && !sY) { sY = (pY < 1) ? -1 : 1; }
|
160 |
|
161 | return { spinX : sX,
|
162 | spinY : sY,
|
163 | pixelX : pX,
|
164 | pixelY : pY };
|
165 | }
|
166 |
|
167 |
|
168 | /**
|
169 | * The best combination if you prefer spinX + spinY normalization. It favors
|
170 | * the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with
|
171 | * 'wheel' event, making spin speed determination impossible.
|
172 | */
|
173 | normalizeWheel.getEventType = function() /*string*/ {
|
174 | return (UserAgent_DEPRECATED.firefox())
|
175 | ? 'DOMMouseScroll'
|
176 | : (isEventSupported('wheel'))
|
177 | ? 'wheel'
|
178 | : 'mousewheel';
|
179 | };
|
180 |
|
181 | module.exports = normalizeWheel;
|