touch_handler.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. class TouchHandler {
  2. constructor() {
  3. this.reset();
  4. }
  5. reset() {
  6. this.touch = {
  7. start: { x: -1, y: -1 },
  8. move: { x: -1, y: -1 },
  9. moved: false,
  10. element: null
  11. };
  12. }
  13. calculateDistance() {
  14. if (this.touch.start.x >= -1 && this.touch.move.x >= -1) {
  15. let horizontalDistance = Math.abs(this.touch.move.x - this.touch.start.x);
  16. let verticalDistance = Math.abs(this.touch.move.y - this.touch.start.y);
  17. if (horizontalDistance > 30 && verticalDistance < 70 || this.touch.moved) {
  18. return this.touch.move.x - this.touch.start.x;
  19. }
  20. }
  21. return 0;
  22. }
  23. findElement(element) {
  24. if (element.classList.contains("touch-item")) {
  25. return element;
  26. }
  27. return DomHelper.findParent(element, "touch-item");
  28. }
  29. onTouchStart(event) {
  30. if (event.touches === undefined || event.touches.length !== 1) {
  31. return;
  32. }
  33. this.reset();
  34. this.touch.start.x = event.touches[0].clientX;
  35. this.touch.start.y = event.touches[0].clientY;
  36. this.touch.element = this.findElement(event.touches[0].target);
  37. this.touch.element.style.transitionDuration = "0s";
  38. }
  39. onTouchMove(event) {
  40. if (event.touches === undefined || event.touches.length !== 1 || this.element === null) {
  41. return;
  42. }
  43. this.touch.move.x = event.touches[0].clientX;
  44. this.touch.move.y = event.touches[0].clientY;
  45. let distance = this.calculateDistance();
  46. let absDistance = Math.abs(distance);
  47. if (absDistance > 0) {
  48. this.touch.moved = true;
  49. let tx = absDistance > 75 ? Math.pow(absDistance - 75, 0.5) + 75 : absDistance;
  50. if (distance < 0) {
  51. tx = -tx;
  52. }
  53. this.touch.element.style.transform = "translateX(" + tx + "px)";
  54. event.preventDefault();
  55. }
  56. }
  57. onTouchEnd(event) {
  58. if (event.touches === undefined) {
  59. return;
  60. }
  61. if (this.touch.element !== null) {
  62. let distance = Math.abs(this.calculateDistance());
  63. if (distance > 75) {
  64. toggleEntryStatus(this.touch.element);
  65. }
  66. if (this.touch.moved) {
  67. this.touch.element.style.transitionDuration = "0.15s";
  68. this.touch.element.style.transform = "none";
  69. }
  70. }
  71. this.reset();
  72. }
  73. listen() {
  74. let elements = document.querySelectorAll(".touch-item");
  75. let hasPassiveOption = DomHelper.hasPassiveEventListenerOption();
  76. elements.forEach((element) => {
  77. element.addEventListener("touchstart", (e) => this.onTouchStart(e), hasPassiveOption ? { passive: true } : false);
  78. element.addEventListener("touchmove", (e) => this.onTouchMove(e), hasPassiveOption ? { passive: false } : false);
  79. element.addEventListener("touchend", (e) => this.onTouchEnd(e), hasPassiveOption ? { passive: true } : false);
  80. element.addEventListener("touchcancel", () => this.reset(), hasPassiveOption ? { passive: true } : false);
  81. });
  82. let entryContentElement = document.querySelector(".entry-content");
  83. if (entryContentElement) {
  84. let doubleTapTimers = {
  85. previous: null,
  86. next: null
  87. };
  88. const detectDoubleTap = (doubleTapTimer, event) => {
  89. const timer = doubleTapTimers[doubleTapTimer];
  90. if (timer === null) {
  91. doubleTapTimers[doubleTapTimer] = setTimeout(() => {
  92. doubleTapTimers[doubleTapTimer] = null;
  93. }, 200);
  94. } else {
  95. event.preventDefault();
  96. goToPage(doubleTapTimer);
  97. }
  98. };
  99. entryContentElement.addEventListener("touchend", (e) => {
  100. if (e.changedTouches[0].clientX >= (entryContentElement.offsetWidth / 2)) {
  101. detectDoubleTap("next", e);
  102. } else {
  103. detectDoubleTap("previous", e);
  104. }
  105. }, hasPassiveOption ? { passive: false } : false);
  106. entryContentElement.addEventListener("touchmove", (e) => {
  107. Object.keys(doubleTapTimers).forEach(timer => doubleTapTimers[timer] = null);
  108. });
  109. }
  110. }
  111. }