UNPKG

d2-ui

Version:
180 lines (164 loc) 6.94 kB
/** * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule ResponderTouchHistoryStore */ 'use strict'; var EventPluginUtils = require('./EventPluginUtils'); var invariant = require('fbjs/lib/invariant'); var isMoveish = EventPluginUtils.isMoveish; var isStartish = EventPluginUtils.isStartish; var isEndish = EventPluginUtils.isEndish; var MAX_TOUCH_BANK = 20; /** * Touch position/time tracking information by touchID. Typically, we'll only * see IDs with a range of 1-20 (they are recycled when touches end and then * start again). This data is commonly needed by many different interaction * logic modules so precomputing it is very helpful to do once. * Each touch object in `touchBank` is of the following form: * { touchActive: boolean, * startTimeStamp: number, * startPageX: number, * startPageY: number, * currentPageX: number, * currentPageY: number, * currentTimeStamp: number * } */ var touchHistory = { touchBank: [], numberActiveTouches: 0, // If there is only one active touch, we remember its location. This prevents // us having to loop through all of the touches all the time in the most // common case. indexOfSingleActiveTouch: -1, 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. * @param {Touch} touch Native touch object. */ var initializeTouchData = function (touch) { return { touchActive: true, startTimeStamp: timestampForTouch(touch), startPageX: touch.pageX, startPageY: touch.pageY, currentPageX: touch.pageX, currentPageY: touch.pageY, currentTimeStamp: timestampForTouch(touch), previousPageX: touch.pageX, previousPageY: touch.pageY, previousTimeStamp: timestampForTouch(touch) }; }; var reinitializeTouchTrack = function (touchTrack, touch) { touchTrack.touchActive = true; touchTrack.startTimeStamp = timestampForTouch(touch); touchTrack.startPageX = touch.pageX; touchTrack.startPageY = touch.pageY; touchTrack.currentPageX = touch.pageX; touchTrack.currentPageY = touch.pageY; touchTrack.currentTimeStamp = timestampForTouch(touch); touchTrack.previousPageX = touch.pageX; touchTrack.previousPageY = touch.pageY; touchTrack.previousTimeStamp = timestampForTouch(touch); }; var validateTouch = function (touch) { var identifier = touch.identifier; !(identifier != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Touch object is missing identifier') : invariant(false) : undefined; if (identifier > MAX_TOUCH_BANK) { console.warn('Touch identifier ' + identifier + ' is greater than maximum ' + 'supported ' + MAX_TOUCH_BANK + ' which causes performance issues ' + 'backfilling array locations for all of the indices.'); } }; var recordStartTouchData = function (touch) { var touchBank = touchHistory.touchBank; var identifier = touch.identifier; var touchTrack = touchBank[identifier]; if (process.env.NODE_ENV !== 'production') { validateTouch(touch); } if (touchTrack) { reinitializeTouchTrack(touchTrack, touch); } else { touchBank[touch.identifier] = initializeTouchData(touch); } touchHistory.mostRecentTimeStamp = timestampForTouch(touch); }; var recordMoveTouchData = function (touch) { var touchBank = touchHistory.touchBank; var touchTrack = touchBank[touch.identifier]; if (process.env.NODE_ENV !== 'production') { validateTouch(touch); !touchTrack ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Touch data should have been recorded on start') : invariant(false) : undefined; } touchTrack.touchActive = true; touchTrack.previousPageX = touchTrack.currentPageX; touchTrack.previousPageY = touchTrack.currentPageY; touchTrack.previousTimeStamp = touchTrack.currentTimeStamp; touchTrack.currentPageX = touch.pageX; touchTrack.currentPageY = touch.pageY; touchTrack.currentTimeStamp = timestampForTouch(touch); touchHistory.mostRecentTimeStamp = timestampForTouch(touch); }; var recordEndTouchData = function (touch) { var touchBank = touchHistory.touchBank; var touchTrack = touchBank[touch.identifier]; if (process.env.NODE_ENV !== 'production') { validateTouch(touch); !touchTrack ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Touch data should have been recorded on start') : invariant(false) : undefined; } touchTrack.previousPageX = touchTrack.currentPageX; touchTrack.previousPageY = touchTrack.currentPageY; touchTrack.previousTimeStamp = touchTrack.currentTimeStamp; touchTrack.currentPageX = touch.pageX; touchTrack.currentPageY = touch.pageY; touchTrack.currentTimeStamp = timestampForTouch(touch); touchTrack.touchActive = false; touchHistory.mostRecentTimeStamp = timestampForTouch(touch); }; var ResponderTouchHistoryStore = { recordTouchTrack: function (topLevelType, nativeEvent) { var touchBank = touchHistory.touchBank; if (isMoveish(topLevelType)) { nativeEvent.changedTouches.forEach(recordMoveTouchData); } else if (isStartish(topLevelType)) { nativeEvent.changedTouches.forEach(recordStartTouchData); touchHistory.numberActiveTouches = nativeEvent.touches.length; if (touchHistory.numberActiveTouches === 1) { touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier; } } else if (isEndish(topLevelType)) { nativeEvent.changedTouches.forEach(recordEndTouchData); touchHistory.numberActiveTouches = nativeEvent.touches.length; if (touchHistory.numberActiveTouches === 1) { for (var i = 0; i < touchBank.length; i++) { var touchTrackToCheck = touchBank[i]; if (touchTrackToCheck != null && touchTrackToCheck.touchActive) { touchHistory.indexOfSingleActiveTouch = i; break; } } if (process.env.NODE_ENV !== 'production') { var activeTouchData = touchBank[touchHistory.indexOfSingleActiveTouch]; var foundActive = activeTouchData != null && !!activeTouchData.touchActive; !foundActive ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Cannot find single active touch') : invariant(false) : undefined; } } } }, touchHistory: touchHistory }; module.exports = ResponderTouchHistoryStore;