UNPKG

6.52 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2013-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 */
9
10'use strict';
11
12var _prodInvariant = require('./reactProdInvariant');
13
14var EventPluginUtils = require('./EventPluginUtils');
15
16var invariant = require('fbjs/lib/invariant');
17var warning = require('fbjs/lib/warning');
18
19var isEndish = EventPluginUtils.isEndish,
20 isMoveish = EventPluginUtils.isMoveish,
21 isStartish = EventPluginUtils.isStartish;
22
23/**
24 * Tracks the position and time of each active touch by `touch.identifier`. We
25 * should typically only see IDs in the range of 1-20 because IDs get recycled
26 * when touches end and start again.
27 */
28
29var MAX_TOUCH_BANK = 20;
30var touchBank = [];
31var touchHistory = {
32 touchBank: touchBank,
33 numberActiveTouches: 0,
34 // If there is only one active touch, we remember its location. This prevents
35 // us having to loop through all of the touches all the time in the most
36 // common case.
37 indexOfSingleActiveTouch: -1,
38 mostRecentTimeStamp: 0
39};
40
41function timestampForTouch(touch) {
42 // The legacy internal implementation provides "timeStamp", which has been
43 // renamed to "timestamp". Let both work for now while we iron it out
44 // TODO (evv): rename timeStamp to timestamp in internal code
45 return touch.timeStamp || touch.timestamp;
46}
47
48/**
49 * TODO: Instead of making gestures recompute filtered velocity, we could
50 * include a built in velocity computation that can be reused globally.
51 */
52function createTouchRecord(touch) {
53 return {
54 touchActive: true,
55 startPageX: touch.pageX,
56 startPageY: touch.pageY,
57 startTimeStamp: timestampForTouch(touch),
58 currentPageX: touch.pageX,
59 currentPageY: touch.pageY,
60 currentTimeStamp: timestampForTouch(touch),
61 previousPageX: touch.pageX,
62 previousPageY: touch.pageY,
63 previousTimeStamp: timestampForTouch(touch)
64 };
65}
66
67function resetTouchRecord(touchRecord, touch) {
68 touchRecord.touchActive = true;
69 touchRecord.startPageX = touch.pageX;
70 touchRecord.startPageY = touch.pageY;
71 touchRecord.startTimeStamp = timestampForTouch(touch);
72 touchRecord.currentPageX = touch.pageX;
73 touchRecord.currentPageY = touch.pageY;
74 touchRecord.currentTimeStamp = timestampForTouch(touch);
75 touchRecord.previousPageX = touch.pageX;
76 touchRecord.previousPageY = touch.pageY;
77 touchRecord.previousTimeStamp = timestampForTouch(touch);
78}
79
80function getTouchIdentifier(_ref) {
81 var identifier = _ref.identifier;
82
83 !(identifier != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Touch object is missing identifier.') : _prodInvariant('138') : void 0;
84 process.env.NODE_ENV !== 'production' ? warning(identifier <= MAX_TOUCH_BANK, 'Touch identifier %s is greater than maximum supported %s which causes ' + 'performance issues backfilling array locations for all of the indices.', identifier, MAX_TOUCH_BANK) : void 0;
85 return identifier;
86}
87
88function recordTouchStart(touch) {
89 var identifier = getTouchIdentifier(touch);
90 var touchRecord = touchBank[identifier];
91 if (touchRecord) {
92 resetTouchRecord(touchRecord, touch);
93 } else {
94 touchBank[identifier] = createTouchRecord(touch);
95 }
96 touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
97}
98
99function recordTouchMove(touch) {
100 var touchRecord = touchBank[getTouchIdentifier(touch)];
101 if (touchRecord) {
102 touchRecord.touchActive = true;
103 touchRecord.previousPageX = touchRecord.currentPageX;
104 touchRecord.previousPageY = touchRecord.currentPageY;
105 touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
106 touchRecord.currentPageX = touch.pageX;
107 touchRecord.currentPageY = touch.pageY;
108 touchRecord.currentTimeStamp = timestampForTouch(touch);
109 touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
110 } else {
111 console.error('Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n', 'Touch Bank: %s', printTouch(touch), printTouchBank());
112 }
113}
114
115function recordTouchEnd(touch) {
116 var touchRecord = touchBank[getTouchIdentifier(touch)];
117 if (touchRecord) {
118 touchRecord.touchActive = false;
119 touchRecord.previousPageX = touchRecord.currentPageX;
120 touchRecord.previousPageY = touchRecord.currentPageY;
121 touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
122 touchRecord.currentPageX = touch.pageX;
123 touchRecord.currentPageY = touch.pageY;
124 touchRecord.currentTimeStamp = timestampForTouch(touch);
125 touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
126 } else {
127 console.error('Cannot record touch end without a touch start.\n' + 'Touch End: %s\n', 'Touch Bank: %s', printTouch(touch), printTouchBank());
128 }
129}
130
131function printTouch(touch) {
132 return JSON.stringify({
133 identifier: touch.identifier,
134 pageX: touch.pageX,
135 pageY: touch.pageY,
136 timestamp: timestampForTouch(touch)
137 });
138}
139
140function printTouchBank() {
141 var printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
142 if (touchBank.length > MAX_TOUCH_BANK) {
143 printed += ' (original size: ' + touchBank.length + ')';
144 }
145 return printed;
146}
147
148var ResponderTouchHistoryStore = {
149 recordTouchTrack: function (topLevelType, nativeEvent) {
150 if (isMoveish(topLevelType)) {
151 nativeEvent.changedTouches.forEach(recordTouchMove);
152 } else if (isStartish(topLevelType)) {
153 nativeEvent.changedTouches.forEach(recordTouchStart);
154 touchHistory.numberActiveTouches = nativeEvent.touches.length;
155 if (touchHistory.numberActiveTouches === 1) {
156 touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier;
157 }
158 } else if (isEndish(topLevelType)) {
159 nativeEvent.changedTouches.forEach(recordTouchEnd);
160 touchHistory.numberActiveTouches = nativeEvent.touches.length;
161 if (touchHistory.numberActiveTouches === 1) {
162 for (var i = 0; i < touchBank.length; i++) {
163 var touchTrackToCheck = touchBank[i];
164 if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
165 touchHistory.indexOfSingleActiveTouch = i;
166 break;
167 }
168 }
169 if (process.env.NODE_ENV !== 'production') {
170 var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch];
171 process.env.NODE_ENV !== 'production' ? warning(activeRecord != null && activeRecord.touchActive, 'Cannot find single active touch.') : void 0;
172 }
173 }
174 }
175 },
176
177
178 touchHistory: touchHistory
179};
180
181module.exports = ResponderTouchHistoryStore;
\No newline at end of file