UNPKG

6.7 kBJavaScriptView Raw
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'use strict';
14
15var UserAgent_DEPRECATED = require('./UserAgent_DEPRECATED');
16
17var isEventSupported = require('./isEventSupported');
18
19
20// Reasonable defaults
21var PIXEL_STEP = 10;
22var LINE_HEIGHT = 40;
23var 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 */
125function 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 */
173normalizeWheel.getEventType = function() /*string*/ {
174 return (UserAgent_DEPRECATED.firefox())
175 ? 'DOMMouseScroll'
176 : (isEventSupported('wheel'))
177 ? 'wheel'
178 : 'mousewheel';
179};
180
181module.exports = normalizeWheel;