Second Update from Tue 24 Mar

This commit is contained in:
Christopher Chedeau
2015-03-24 19:34:12 -07:00
parent 8068c65f12
commit ead3a740ca
121 changed files with 6808 additions and 667 deletions

View File

@@ -0,0 +1,275 @@
/**
* @providesModule PanResponder
*/
"use strict";
var TouchHistoryMath = require('TouchHistoryMath');
var currentCentroidXOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
var currentCentroidYOfTouchesChangedAfter =
TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
var previousCentroidXOfTouchesChangedAfter =
TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
var previousCentroidYOfTouchesChangedAfter =
TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
var currentCentroidX = TouchHistoryMath.currentCentroidX;
var currentCentroidY = TouchHistoryMath.currentCentroidY;
/**
*
* +----------------------------+ +--------------------------------+
* | ResponderTouchHistoryStore | |TouchHistoryMath |
* +----------------------------+ +----------+---------------------+
* |Global store of touchHistory| |Allocation-less math util |
* |including activeness, start | |on touch history (centroids |
* |position, prev/cur position.| |and multitouch movement etc) |
* | | | |
* +----^-----------------------+ +----^---------------------------+
* | |
* | (records relevant history |
* | of touches relevant for |
* | implementing higher level |
* | gestures) |
* | |
* +----+-----------------------+ +----|---------------------------+
* | ResponderEventPlugin | | | Your App/Component |
* +----------------------------+ +----|---------------------------+
* |Negotiates which view gets | Low level | | High level |
* |onResponderMove events. | events w/ | +-+-------+ events w/ |
* |Also records history into | touchHistory| | Pan | multitouch + |
* |ResponderTouchHistoryStore. +---------------->Responder+-----> accumulative|
* +----------------------------+ attached to | | | distance and |
* each event | +---------+ velocity. |
* | |
* | |
* +--------------------------------+
*
*
*
* Gesture that calculates cumulative movement over time in a way that just
* "does the right thing" for multiple touches. The "right thing" is very
* nuanced. When moving two touches in opposite directions, the cumulative
* distance is zero in each dimension. When two touches move in parallel five
* pixels in the same direction, the cumulative distance is five, not ten. If
* two touches start, one moves five in a direction, then stops and the other
* touch moves fives in the same direction, the cumulative distance is ten.
*
* This logic requires a kind of processing of time "clusters" of touch events
* so that two touch moves that essentially occur in parallel but move every
* other frame respectively, are considered part of the same movement.
*
* Explanation of some of the non-obvious fields:
*
* - moveX/moveY: If no move event has been observed, then `(moveX, moveY)` is
* invalid. If a move event has been observed, `(moveX, moveY)` is the
* centroid of the most recently moved "cluster" of active touches.
* (Currently all move have the same timeStamp, but later we should add some
* threshold for what is considered to be "moving"). If a palm is
* accidentally counted as a touch, but a finger is moving greatly, the palm
* will move slightly, but we only want to count the single moving touch.
* - x0/y0: Centroid location (non-cumulative) at the time of becoming
* responder.
* - dx/dy: Cumulative touch distance - not the same thing as sum of each touch
* distance. Accounts for touch moves that are clustered together in time,
* moving the same direction. Only valid when currently responder (otherwise,
* it only represents the drag distance below the threshold).
* - vx/vy: Velocity.
*/
var PanResponder = {
_initializeGestureState: function(gestureState) {
gestureState.moveX = 0;
gestureState.moveY = 0;
gestureState.x0 = 0;
gestureState.y0 = 0;
gestureState.dx = 0;
gestureState.dy = 0;
gestureState.vx = 0;
gestureState.vy = 0;
gestureState.numberActiveTouches = 0;
// All `gestureState` accounts for timeStamps up until:
gestureState._accountsForMovesUpTo = 0;
},
/**
* This is nuanced and is necessary. It is incorrect to continuously take all
* active *and* recently moved touches, find the centroid, and track how that
* result changes over time. Instead, we must take all recently moved
* touches, and calculate how the centroid has changed just for those
* recently moved touches, and append that change to an accumulator. This is
* to (at least) handle the case where the user is moving three fingers, and
* then one of the fingers stops but the other two continue.
*
* This is very different than taking all of the recently moved touches and
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
* changes* in the centroid of recently moved touches.
*
* There is also some nuance with how we handle multiple moved touches in a
* single event. With the way `ReactIOSEventEmitter` dispatches touches as
* individual events, multiple touches generate two 'move' events, each of
* them triggering `onResponderMove`. But with the way `PanResponder` works,
* all of the gesture inference is performed on the first dispatch, since it
* looks at all of the touches (even the ones for which there hasn't been a
* native dispatch yet). Therefore, `PanResponder` does not call
* `onResponderMove` passed the first dispatch. This diverges from the
* typical responder callback pattern (without using `PanResponder`), but
* avoids more dispatches than necessary.
*/
_updateGestureStateOnMove: function(gestureState, touchHistory) {
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(
touchHistory,
gestureState._accountsForMovesUpTo
);
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(
touchHistory,
gestureState._accountsForMovesUpTo
);
var movedAfter = gestureState._accountsForMovesUpTo;
var prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
var x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
var prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
var y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
var nextDX = gestureState.dx + (x - prevX);
var nextDY = gestureState.dy + (y - prevY);
// TODO: This must be filtered intelligently.
var dt =
(touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo);
gestureState.vx = (nextDX - gestureState.dx) / dt;
gestureState.vy = (nextDY - gestureState.dy) / dt;
gestureState.dx = nextDX;
gestureState.dy = nextDY;
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
},
/**
* @param {object} config Enhanced versions of all of the responder callbacks
* that accept not only the typical `ResponderSyntheticEvent`, but also the
* `PanResponder` gesture state. Simply replace the word `Responder` with
* `PanResponder` in each of the typical `onResponder*` callbacks. For
* example, the `config` object would look like:
*
* - onMoveShouldSetPanResponder: (e, gestureState) => {...}
* - onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
* - onStartShouldSetPanResponder: (e, gestureState) => {...}
* - onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
* - onPanResponderReject: (e, gestureState) => {...}
* - onPanResponderGrant: (e, gestureState) => {...}
* - onPanResponderStart: (e, gestureState) => {...}
* - onPanResponderEnd: (e, gestureState) => {...}
* - onPanResponderRelease: (e, gestureState) => {...}
* - onPanResponderMove: (e, gestureState) => {...}
* - onPanResponderTerminate: (e, gestureState) => {...}
* - onPanResponderTerminationRequest: (e, gestureState) => {...}
*
* - In general, for events that have capture equivalents, we update the
* gestureState once in the capture phase and can use it in the bubble phase
* as well.
*
* - Be careful with onStartShould* callbacks. They only reflect updated
* `gestureState` for start/end events that bubble/capture to the Node.
* Once the node is the responder, you can rely on every start/end event
* being processed by the gesture and `gestureState` being updated
* accordingly. (numberActiveTouches) may not be totally accurate unless you
* are the responder.
*/
create: function(config) {
var gestureState = {
// Useful for debugging
stateID: Math.random(),
};
PanResponder._initializeGestureState(gestureState);
var panHandlers = {
onStartShouldSetResponder: function(e) {
return config.onStartShouldSetPanResponder === undefined ? false :
config.onStartShouldSetPanResponder(e, gestureState);
},
onMoveShouldSetResponder: function(e) {
return config.onMoveShouldSetPanResponder === undefined ? false :
config.onMoveShouldSetPanResponder(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) {
PanResponder._initializeGestureState(gestureState);
}
gestureState.numberActiveTouches = e.touchHistory.numberActiveTouches;
return config.onStartShouldSetPanResponderCapture !== undefined ?
config.onStartShouldSetPanResponderCapture(e, gestureState) : false;
},
onMoveShouldSetResponderCapture: function(e) {
var touchHistory = e.touchHistory;
// Responder system incorrectly dispatches should* to current responder
// Filter out any touch moves past the first one - we would have
// already processed multi-touch geometry during the first event.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return false;
}
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
return config.onMoveShouldSetResponderCapture ?
config.onMoveShouldSetPanResponderCapture(e, gestureState) : false;
},
onResponderGrant: function(e) {
gestureState.x0 = currentCentroidX(e.touchHistory);
gestureState.y0 = currentCentroidY(e.touchHistory);
gestureState.dx = 0;
gestureState.dy = 0;
config.onPanResponderGrant && config.onPanResponderGrant(e, gestureState);
},
onResponderReject: function(e) {
config.onPanResponderReject && config.onPanResponderReject(e, gestureState);
},
onResponderRelease: function(e) {
config.onPanResponderRelease && config.onPanResponderRelease(e, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderStart: function(e) {
var touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderStart && config.onPanResponderStart(e, gestureState);
},
onResponderMove: function(e) {
var touchHistory = e.touchHistory;
// Guard against the dispatch of two touch moves when there are two
// simultaneously changed touches.
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
return;
}
// 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);
},
onResponderEnd: function(e) {
var touchHistory = e.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
config.onPanResponderEnd && config.onPanResponderEnd(e, gestureState);
},
onResponderTerminate: function(e) {
config.onPanResponderTerminate &&
config.onPanResponderTerminate(e, gestureState);
PanResponder._initializeGestureState(gestureState);
},
onResponderTerminationRequest: function(e) {
return config.onPanResponderTerminationRequest === undefined ? true :
config.onPanResponderTerminationRequest(e, gestureState);
},
};
return {panHandlers: panHandlers};
},
};
module.exports = PanResponder;

View File

@@ -39,6 +39,13 @@ var touchHistory = {
mostRecentTimeStamp: 0,
};
var timestampForTouch = function(touch) {
// The legacy internal implementation provides "timeStamp", which has been
// renamed to "timestamp". Let both work for now while we iron it out
// TODO (evv): rename timeStamp to timestamp in internal code
return touch.timeStamp || touch.timestamp;
};
/**
* TODO: Instead of making gestures recompute filtered velocity, we could
* include a built in velocity computation that can be reused globally.
@@ -47,29 +54,29 @@ var touchHistory = {
var initializeTouchData = function(touch) {
return {
touchActive: true,
startTimeStamp: touch.timeStamp,
startTimeStamp: timestampForTouch(touch),
startPageX: touch.pageX,
startPageY: touch.pageY,
currentPageX: touch.pageX,
currentPageY: touch.pageY,
currentTimeStamp: touch.timeStamp,
currentTimeStamp: timestampForTouch(touch),
previousPageX: touch.pageX,
previousPageY: touch.pageY,
previousTimeStamp: touch.timeStamp,
previousTimeStamp: timestampForTouch(touch),
};
};
var reinitializeTouchTrack = function(touchTrack, touch) {
touchTrack.touchActive = true;
touchTrack.startTimeStamp = touch.timeStamp;
touchTrack.startTimeStamp = timestampForTouch(touch);
touchTrack.startPageX = touch.pageX;
touchTrack.startPageY = touch.pageY;
touchTrack.currentPageX = touch.pageX;
touchTrack.currentPageY = touch.pageY;
touchTrack.currentTimeStamp = touch.timeStamp;
touchTrack.currentTimeStamp = timestampForTouch(touch);
touchTrack.previousPageX = touch.pageX;
touchTrack.previousPageY = touch.pageY;
touchTrack.previousTimeStamp = touch.timeStamp;
touchTrack.previousTimeStamp = timestampForTouch(touch);
};
var validateTouch = function(touch) {
@@ -96,7 +103,7 @@ var recordStartTouchData = function(touch) {
} else {
reinitializeTouchTrack(touchTrack, touch);
}
touchHistory.mostRecentTimeStamp = touch.timeStamp;
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
};
var recordMoveTouchData = function(touch) {
@@ -112,8 +119,8 @@ var recordMoveTouchData = function(touch) {
touchTrack.previousTimeStamp = touchTrack.currentTimeStamp;
touchTrack.currentPageX = touch.pageX;
touchTrack.currentPageY = touch.pageY;
touchTrack.currentTimeStamp = touch.timeStamp;
touchHistory.mostRecentTimeStamp = touch.timeStamp;
touchTrack.currentTimeStamp = timestampForTouch(touch);
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
};
var recordEndTouchData = function(touch) {
@@ -128,9 +135,9 @@ var recordEndTouchData = function(touch) {
touchTrack.previousTimeStamp = touchTrack.currentTimeStamp;
touchTrack.currentPageX = touch.pageX;
touchTrack.currentPageY = touch.pageY;
touchTrack.currentTimeStamp = touch.timeStamp;
touchTrack.currentTimeStamp = timestampForTouch(touch);
touchTrack.touchActive = false;
touchHistory.mostRecentTimeStamp = touch.timeStamp;
touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
};
var ResponderTouchHistoryStore = {

View File

@@ -0,0 +1,122 @@
/**
* @providesModule TouchHistoryMath
*/
"use strict";
var TouchHistoryMath = {
/**
* This code is optimized and not intended to look beautiful. This allows
* computing of touch centroids that have moved after `touchesChangedAfter`
* timeStamp. You can compute the current centroid involving all touches
* moves after `touchesChangedAfter`, or you can compute the previous
* centroid of all touches that were moved after `touchesChangedAfter`.
*
* @param {TouchHistoryMath} touchHistory Standard Responder touch track
* data.
* @param {number} touchesChangedAfter timeStamp after which moved touches
* are considered "actively moving" - not just "active".
* @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension.
* @param {boolean} ofCurrent Compute current centroid for actively moving
* touches vs. previous centroid of now actively moving touches.
* @return {number} value of centroid in specified dimension.
*/
centroidDimension: function(touchHistory, touchesChangedAfter, isXAxis, ofCurrent) {
var touchBank = touchHistory.touchBank;
var total = 0;
var count = 0;
var oneTouchData = touchHistory.numberActiveTouches === 1 ?
touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] : null;
if (oneTouchData !== null) {
if (oneTouchData.touchActive && oneTouchData.currentTimeStamp > touchesChangedAfter) {
total += ofCurrent && isXAxis ? oneTouchData.currentPageX :
ofCurrent && !isXAxis ? oneTouchData.currentPageY :
!ofCurrent && isXAxis ? oneTouchData.previousPageX :
oneTouchData.previousPageY;
count = 1;
}
} else {
for (var i = 0; i < touchBank.length; i++) {
var touchTrack = touchBank[i];
if (touchTrack !== null &&
touchTrack !== undefined &&
touchTrack.touchActive &&
touchTrack.currentTimeStamp >= touchesChangedAfter) {
var toAdd; // Yuck, program temporarily in invalid state.
if (ofCurrent && isXAxis) {
toAdd = touchTrack.currentPageX;
} else if (ofCurrent && !isXAxis) {
toAdd = touchTrack.currentPageY;
} else if (!ofCurrent && isXAxis) {
toAdd = touchTrack.previousPageX;
} else {
toAdd = touchTrack.previousPageY;
}
total += toAdd;
count++;
}
}
}
return count > 0 ? total / count : TouchHistoryMath.noCentroid;
},
currentCentroidXOfTouchesChangedAfter: function(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(
touchHistory,
touchesChangedAfter,
true, // isXAxis
true // ofCurrent
);
},
currentCentroidYOfTouchesChangedAfter: function(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(
touchHistory,
touchesChangedAfter,
false, // isXAxis
true // ofCurrent
);
},
previousCentroidXOfTouchesChangedAfter: function(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(
touchHistory,
touchesChangedAfter,
true, // isXAxis
false // ofCurrent
);
},
previousCentroidYOfTouchesChangedAfter: function(touchHistory, touchesChangedAfter) {
return TouchHistoryMath.centroidDimension(
touchHistory,
touchesChangedAfter,
false, // isXAxis
false // ofCurrent
);
},
currentCentroidX: function(touchHistory) {
return TouchHistoryMath.centroidDimension(
touchHistory,
0, // touchesChangedAfter
true, // isXAxis
true // ofCurrent
);
},
currentCentroidY: function(touchHistory) {
return TouchHistoryMath.centroidDimension(
touchHistory,
0, // touchesChangedAfter
false, // isXAxis
true // ofCurrent
);
},
noCentroid: -1,
};
module.exports = TouchHistoryMath;

35
Libraries/vendor/react/core/clamp.js vendored Normal file
View File

@@ -0,0 +1,35 @@
/**
* @generated SignedSource<<ec51291ea6059cf23faa74f8644d17b1>>
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !! This file is a check-in of a static_upstream project! !!
* !! !!
* !! You should not modify this file directly. Instead: !!
* !! 1) Use `fjs use-upstream` to temporarily replace this with !!
* !! the latest version from upstream. !!
* !! 2) Make your changes, test them, etc. !!
* !! 3) Use `fjs push-upstream` to copy your changes back to !!
* !! static_upstream. !!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* @providesModule clamp
* @typechecks
*/
/**
* @param {number} value
* @param {number} min
* @param {number} max
* @return {number}
*/
function clamp(min, value, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
module.exports = clamp;