UNPKG

@baleada/listenable-gestures

Version:

A collection of gesture recognizers that are compatible with Baleada Logic's Listenable class.

171 lines (153 loc) 4.97 kB
import { emit, toEmitted, naiveDeepClone, getGetPoint, isDefined } from '../util'; /* * taps is defined as a single touch that: * - starts at a given point * - does not move beyond a maximum distance * - does not cancel * - ends * - repeats 1 time (or a minimum number of your choice), with each tap ending less than or equal to 500ms (or a maximum interval of your choice) after the previous tap ended */ var defaultOptions = { minTaps: 1, maxInterval: 500, // Via https://ux.stackexchange.com/questions/40364/what-is-the-expected-timeframe-of-a-double-click maxDistance: 5 // TODO: research appropriate/accessible minDistance }; export default function taps() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var onStart = options.onStart, onMove = options.onMove, onCancel = options.onCancel, onEnd = options.onEnd, minTaps = isDefined(options.minTaps) ? options.minTaps : defaultOptions.minTaps, maxInterval = isDefined(options.maxInterval) ? options.maxInterval : defaultOptions.maxInterval, maxDistance = isDefined(options.maxDistance) ? options.maxDistance : defaultOptions.maxDistance; function touchstart(handlerApi) { var event = handlerApi.event, setMetadata = handlerApi.setMetadata; setMetadata({ path: 'touchTotal', value: event.touches.length }); setMetadata({ path: 'lastTap.times.start', value: event.timeStamp }); var getPoint = getGetPoint('touch'); setMetadata({ path: 'lastTap.points.start', value: getPoint(event) }); emit(onStart, toEmitted(handlerApi)); } function touchmove(handlerApi) { emit(onMove, toEmitted(handlerApi)); } function touchcancel(handlerApi) { var getMetadata = handlerApi.getMetadata, denied = handlerApi.denied; if (getMetadata().touchTotal === 1) { denied(); setMetadata({ path: 'touchTotal', value: getMetadata().touchTotal - 1 }); // TODO: is there a way to un-cancel a touch without triggering a touch start? If so, this touch total calc would be wrong. } emit(onCancel, toEmitted(handlerApi)); } function touchend(handlerApi) { var event = handlerApi.event, getMetadata = handlerApi.getMetadata, toPolarCoordinates = handlerApi.toPolarCoordinates, setMetadata = handlerApi.setMetadata, pushMetadata = handlerApi.pushMetadata, denied = handlerApi.denied; setMetadata({ path: 'touchTotal', value: getMetadata().touchTotal - 1 }); if (getMetadata().touchTotal === 0) { var _getMetadata$lastTap$ = getMetadata().lastTap.points.start, xA = _getMetadata$lastTap$.x, yA = _getMetadata$lastTap$.y, _event$changedTouches = event.changedTouches.item(0), xB = _event$changedTouches.clientX, yB = _event$changedTouches.clientY, _toPolarCoordinates = toPolarCoordinates({ xA: xA, xB: xB, yA: yA, yB: yB }), distance = _toPolarCoordinates.distance, endPoint = { x: xB, y: yB }, endTime = event.timeStamp; setMetadata({ path: 'lastTap.points.end', value: endPoint }); setMetadata({ path: 'lastTap.times.end', value: endTime }); setMetadata({ path: 'lastTap.distance', value: distance }); if (!Array.isArray(getMetadata().taps)) { setMetadata({ path: 'taps', value: [] }); } var interval = getMetadata().taps.length === 0 ? 0 : endTime - getMetadata().taps[getMetadata().taps.length - 1].times.end; setMetadata({ path: 'lastClick.interval', value: interval }); var newTap = naiveDeepClone(getMetadata().lastTap); pushMetadata({ path: 'taps', value: newTap }); recognize(handlerApi); } else { denied(); } emit(onEnd, toEmitted(handlerApi)); } function recognize(_ref) { var getMetadata = _ref.getMetadata, denied = _ref.denied, recognized = _ref.recognized; switch (true) { case getMetadata().lastTap.interval > maxInterval || getMetadata().lastTap.distance > maxDistance: // Deny after multiple touches and after taps with intervals or movement distances that are too large var lastTap = naiveDeepClone(getMetadata().lastTap); denied(); setMetadata({ path: 'taps', value: [] }); pushMetadata({ path: 'taps', value: lastTap }); break; default: if (getMetadata().taps.length >= minTaps) { recognized(); } break; } } return { touchstart: touchstart, touchmove: touchmove, touchcancel: touchcancel, touchend: touchend }; }