Advertisement
Guest User

Untitled

a guest
Oct 19th, 2019
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.68 KB | None | 0 0
  1. // @flow
  2. import { useState, useLayoutEffect } from 'react';
  3. import type { ElementRef } from 'react';
  4.  
  5. /**
  6. * This react hook allows you to detect dragging and swiping
  7. * @param ref HTML Element ref (react ref)
  8. * @param handler Function Callback
  9. * @param config Object
  10. * @return Function remove listeners
  11. * TODO: Realtime tracking
  12. * */
  13. export function useGestures(
  14. ref: ElementRef<Object>,
  15. handler: Function,
  16. config: { realTime: boolean, delay: number, axis: 'x' | 'y' | 'both' },
  17. ): Object {
  18. const [startX, setStartX] = useState(0);
  19. const [endX, setEndX] = useState(0);
  20. const [startY, setStartY] = useState(0);
  21. const [endY, setEndY] = useState(0);
  22. const [currentX, setCurrentX] = useState(0);
  23. const [currentY, setCurrentY] = useState(0);
  24. const [isMoving, setIsMoving] = useState(false);
  25. const [throttled, setThrottled] = useState(false);
  26.  
  27. const hasMouseEvent = 'onmousedown' in document;
  28. const hasTouchEvent = 'ontouchstart' in document;
  29.  
  30. const cfg = {
  31. realTime: (config && config.realTime) || false, // realtime dragging callback
  32. delay: config && config.delay >= 0 && config.delay < 10000 ? config.delay : 100, // delay between calls in realtime dragging
  33. axis: config && ['x', 'y', 'both'].includes(config.axis) ? config.axis : 'both',
  34. };
  35.  
  36. const onDragStart = e => {
  37. if (e.cancelable) e.preventDefault();
  38.  
  39. if (cfg.axis === 'x' || cfg.axis === 'both')
  40. setStartX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
  41.  
  42. if (cfg.axis === 'y' || cfg.axis === 'both')
  43. setStartY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
  44. };
  45. const onDrag = e => {
  46. if (e.cancelable) e.preventDefault();
  47. if (cfg.realTime) {
  48. if (!throttled) {
  49. // actual callback action
  50. if (cfg.axis === 'x' || cfg.axis === 'both')
  51. setCurrentX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
  52. if (cfg.axis === 'y' || cfg.axis === 'both')
  53. setCurrentY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
  54.  
  55. // we're throttled!
  56. setThrottled(true);
  57.  
  58. // set a timeout to un-throttle
  59. setTimeout(() => {
  60. setThrottled(false);
  61. }, cfg.delay);
  62. }
  63. }
  64. setIsMoving(true);
  65. };
  66. const onDragEnd = e => {
  67. if (e.cancelable) e.preventDefault();
  68. if (cfg.axis === 'x' || cfg.axis === 'both')
  69. setEndX(parseInt((e.changedTouches && e.changedTouches[0].screenX) || e.screenX, 10));
  70. if (cfg.axis === 'y' || cfg.axis === 'both')
  71. setEndY(parseInt((e.changedTouches && e.changedTouches[0].screenY) || e.screenY, 10));
  72.  
  73. setIsMoving(false);
  74. };
  75. const onMouseLeave = e => {
  76. if (e.cancelable) e.preventDefault();
  77.  
  78. setIsMoving(false);
  79. };
  80.  
  81. const addListeners = gesuredZone => {
  82. if (hasMouseEvent) {
  83. gesuredZone.addEventListener('mousedown', onDragStart, false);
  84. gesuredZone.addEventListener('mousemove', onDrag);
  85. gesuredZone.addEventListener('mouseup', onDragEnd);
  86. gesuredZone.addEventListener('mouseleave', onMouseLeave);
  87. }
  88. if (hasTouchEvent) {
  89. gesuredZone.addEventListener('touchstart', onDragStart, false);
  90. gesuredZone.addEventListener('touchmove', onDrag);
  91. gesuredZone.addEventListener('touchend', onDragEnd);
  92. }
  93. };
  94.  
  95. const removeListeners = gesuredZone => {
  96. if (hasMouseEvent) {
  97. gesuredZone.removeEventListener('mousedown', onDragStart);
  98. gesuredZone.removeEventListener('mousemove', onDrag);
  99. gesuredZone.removeEventListener('mouseup', onDragEnd);
  100. gesuredZone.removeEventListener('mouseleave', onMouseLeave);
  101. }
  102. if (hasTouchEvent) {
  103. gesuredZone.removeEventListener('touchstart', onDragStart);
  104. gesuredZone.removeEventListener('touchmove', onDrag);
  105. gesuredZone.removeEventListener('touchend', onDragEnd);
  106. }
  107. };
  108.  
  109. useEffect(() => {
  110. addListeners(ref.current);
  111.  
  112. // TODO: Direction on real time
  113. let direction = 'same';
  114.  
  115. if (cfg.realTime) {
  116. if (currentX > startX) direction = 'right';
  117. if (currentX < startX) direction = 'left';
  118. } else {
  119. if (startX > endX) direction = 'left';
  120. if (startX < endX) direction = 'right';
  121. }
  122.  
  123. let res = { isMoving, direction };
  124.  
  125. if (cfg.axis === 'x' || cfg.axis === 'both') res = { startX, endX, ...res };
  126. if (cfg.axis === 'y' || cfg.axis === 'both') res = { startY, endY, ...res };
  127. if (cfg.realTime && (cfg.axis === 'x' || cfg.axis === 'both')) res = { currentX, ...res };
  128. if (cfg.realTime && (cfg.axis === 'y' || cfg.axis === 'both')) res = { currentY, ...res };
  129.  
  130. if (startX || startY || endX || endY) handler(res);
  131.  
  132. return () => removeListeners(ref.current);
  133. }, [endX, endY, throttled]);
  134. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement