[fix] PanResponder improvements + mouse support

- Adds `locationX` and `locationY` to touch events
- Adds `timestamp` to the `touches` and `touchesChanged` data
- Add mouse event support

Close #94
This commit is contained in:
IjzerenHein
2016-03-11 15:09:18 +01:00
committed by Nicolas Gallagher
parent 6d7d98c149
commit f6f8d30aba
3 changed files with 113 additions and 56 deletions
+24 -12
View File
@@ -6,6 +6,7 @@
"use strict";
import normalizeNativeEvent from './normalizeNativeEvent';
var TouchHistoryMath = require('./TouchHistoryMath');
var currentCentroidXOfTouchesChangedAfter =
@@ -287,21 +288,26 @@ var PanResponder = {
var panHandlers = {
onStartShouldSetResponder: function(e) {
return config.onStartShouldSetPanResponder === undefined ? false :
config.onStartShouldSetPanResponder(e, gestureState);
config.onStartShouldSetPanResponder(normalizeEvent(e), gestureState);
},
onMoveShouldSetResponder: function(e) {
return config.onMoveShouldSetPanResponder === undefined ? false :
config.onMoveShouldSetPanResponder(e, gestureState);
config.onMoveShouldSetPanResponder(normalizeEvent(e), gestureState);
},
onStartShouldSetResponderCapture: function(e) {
// TODO: Actually, we should reinitialize the state any time
// touches.length increases from 0 active to > 0 active.
if (e.nativeEvent.touches.length === 1) {
if (e.nativeEvent.touches) {
if (e.nativeEvent.touches.length === 1) {
PanResponder._initializeGestureState(gestureState);
}
}
else if (e.nativeEvent.type === 'mousedown') {
PanResponder._initializeGestureState(gestureState);
}
gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
return config.onStartShouldSetPanResponderCapture !== undefined ?
config.onStartShouldSetPanResponderCapture(e, gestureState) : false;
config.onStartShouldSetPanResponderCapture(normalizeEvent(e), gestureState) : false;
},
onMoveShouldSetResponderCapture: function(e) {
@@ -314,7 +320,7 @@ var PanResponder = {
}
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
return config.onMoveShouldSetPanResponderCapture ?
config.onMoveShouldSetPanResponderCapture(e, gestureState) : false;
config.onMoveShouldSetPanResponderCapture(normalizeEvent(e), gestureState) : false;
},
onResponderGrant: function(e) {
@@ -322,25 +328,25 @@ var PanResponder = {
gestureState.y0 = currentCentroidY(e.touchHistory);
gestureState.dx = 0;
gestureState.dy = 0;
config.onPanResponderGrant && config.onPanResponderGrant(e, gestureState);
config.onPanResponderGrant && config.onPanResponderGrant(normalizeEvent(e), gestureState);
// TODO: t7467124 investigate if this can be removed
return config.onShouldBlockNativeResponder === undefined ? true :
config.onShouldBlockNativeResponder();
},
onResponderReject: function(e) {
config.onPanResponderReject && config.onPanResponderReject(e, gestureState);
config.onPanResponderReject && config.onPanResponderReject(normalizeEvent(e), gestureState);
},
onResponderRelease: function(e) {
config.onPanResponderRelease && config.onPanResponderRelease(e, gestureState);
config.onPanResponderRelease && config.onPanResponderRelease(normalizeEvent(e), gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderStart: function(e) {
var touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderStart && config.onPanResponderStart(e, gestureState);
config.onPanResponderStart && config.onPanResponderStart(normalizeEvent(e), gestureState);
},
onResponderMove: function(e) {
@@ -353,13 +359,13 @@ var PanResponder = {
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
config.onPanResponderMove && config.onPanResponderMove(e, gestureState);
config.onPanResponderMove && config.onPanResponderMove(normalizeEvent(e), gestureState);
},
onResponderEnd: function(e) {
var touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderEnd && config.onPanResponderEnd(e, gestureState);
config.onPanResponderEnd && config.onPanResponderEnd(normalizeEvent(e), gestureState);
},
onResponderTerminate: function(e) {
@@ -370,11 +376,17 @@ var PanResponder = {
onResponderTerminationRequest: function(e) {
return config.onPanResponderTerminationRequest === undefined ? true :
config.onPanResponderTerminationRequest(e, gestureState);
config.onPanResponderTerminationRequest(normalizeEvent(e), gestureState);
},
};
return {panHandlers: panHandlers};
},
};
function normalizeEvent(e) {
const normalizedEvent = Object.create(e);
normalizedEvent.nativeEvent = normalizeNativeEvent(e.nativeEvent, e.type);
return normalizedEvent;
}
module.exports = PanResponder;
@@ -4,6 +4,7 @@ import EventConstants from 'react/lib/EventConstants'
import EventPluginRegistry from 'react/lib/EventPluginRegistry'
import ResponderEventPlugin from 'react/lib/ResponderEventPlugin'
import ResponderTouchHistoryStore from 'react/lib/ResponderTouchHistoryStore'
import normalizeNativeEvent from './normalizeNativeEvent'
const {
topMouseDown,
@@ -37,53 +38,13 @@ ResponderEventPlugin.eventTypes.selectionChangeShouldSetResponder.dependencies =
ResponderEventPlugin.eventTypes.scrollShouldSetResponder.dependencies = [ topScroll ]
ResponderEventPlugin.eventTypes.startShouldSetResponder.dependencies = startDependencies
// Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier
const normalizeTouches = (touches = []) => Array.prototype.slice.call(touches).map((touch) => {
const identifier = touch.identifier > 20 ? (touch.identifier % 20) : touch.identifier
return {
clientX: touch.clientX,
clientY: touch.clientY,
force: touch.force,
identifier: identifier,
pageX: touch.pageX,
pageY: touch.pageY,
radiusX: touch.radiusX,
radiusY: touch.radiusY,
rotationAngle: touch.rotationAngle,
screenX: touch.screenX,
screenY: touch.screenY,
target: touch.target
}
})
const normalizeNativeEvent = (nativeEvent) => {
const changedTouches = normalizeTouches(nativeEvent.changedTouches)
const touches = normalizeTouches(nativeEvent.touches)
const event = {
changedTouches,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
target: nativeEvent.target,
// normalize the timestamp
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
timestamp: Date.now(),
touches
}
if (changedTouches[0]) {
event.identifier = changedTouches[0].identifier
event.pageX = changedTouches[0].pageX
event.pageY = changedTouches[0].pageY
}
return event
}
const originalRecordTouchTrack = ResponderTouchHistoryStore.recordTouchTrack
ResponderTouchHistoryStore.recordTouchTrack = (topLevelType, nativeEvent) => {
// Filter out mouse-move events when the mouse button is not down
if ((topLevelType === 'topMouseMove') && !ResponderTouchHistoryStore.touchHistory.touchBank.length) {
return
}
originalRecordTouchTrack.call(ResponderTouchHistoryStore, topLevelType, normalizeNativeEvent(nativeEvent))
}
@@ -0,0 +1,84 @@
// Mobile Safari re-uses touch objects, so we copy the properties we want and normalize the identifier
const normalizeTouches = (touches = []) => Array.prototype.slice.call(touches).map((touch) => {
const identifier = touch.identifier > 20 ? (touch.identifier % 20) : touch.identifier
return {
clientX: touch.clientX,
clientY: touch.clientY,
force: touch.force,
identifier: identifier,
pageX: touch.pageX,
pageY: touch.pageY,
radiusX: touch.radiusX,
radiusY: touch.radiusY,
rotationAngle: touch.rotationAngle,
screenX: touch.screenX,
screenY: touch.screenY,
target: touch.target,
// normalize the timestamp
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
timestamp: Date.now()
}
})
function normalizeTouchEvent(nativeEvent) {
const changedTouches = normalizeTouches(nativeEvent.changedTouches)
const touches = normalizeTouches(nativeEvent.touches)
const event = {
changedTouches,
domEvent: nativeEvent,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
target: nativeEvent.target,
// normalize the timestamp
// https://stackoverflow.com/questions/26177087/ios-8-mobile-safari-wrong-timestamp-on-touch-events
timestamp: Date.now(),
touches
}
if (changedTouches[0]) {
event.identifier = changedTouches[0].identifier
event.pageX = changedTouches[0].pageX
event.pageY = changedTouches[0].pageY
const rect = changedTouches[0].target.getBoundingClientRect()
event.locationX = changedTouches[0].pageX - rect.left
event.locationY = changedTouches[0].pageY - rect.top
}
return event
}
function normalizeMouseEvent(nativeEvent) {
const touches = [{
clientX: nativeEvent.clientX,
clientY: nativeEvent.clientY,
force: nativeEvent.force,
identifier: 0,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
screenX: nativeEvent.screenX,
screenY: nativeEvent.screenY,
target: nativeEvent.target,
timestamp: nativeEvent.timestamp || Date.now()
}]
return {
changedTouches: touches,
domEvent: nativeEvent,
identifier: touches[0].identifier,
locationX: nativeEvent.offsetX,
locationY: nativeEvent.offsetY,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
target: nativeEvent.target,
timestamp: touches[0].timestamp,
touches: (nativeEvent.type === 'mouseup') ? [] : touches
}
}
function normalizeNativeEvent(nativeEvent) {
const mouse = nativeEvent.type.indexOf('mouse') >= 0
return mouse ? normalizeMouseEvent(nativeEvent) : normalizeTouchEvent(nativeEvent)
}
export default normalizeNativeEvent