alloy_finger.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /* AlloyFinger v0.1.3
  2. * By dntzhang
  3. * Github: https://github.com/AlloyTeam/AlloyFinger
  4. */
  5. ; (function () {
  6. function getLen(v) {
  7. return Math.sqrt(v.x * v.x + v.y * v.y);
  8. }
  9. function dot(v1, v2) {
  10. return v1.x * v2.x + v1.y * v2.y;
  11. }
  12. function getAngle(v1, v2) {
  13. var mr = getLen(v1) * getLen(v2);
  14. if (mr === 0) return 0;
  15. var r = dot(v1, v2) / mr;
  16. if (r > 1) r = 1;
  17. return Math.acos(r);
  18. }
  19. function cross(v1, v2) {
  20. return v1.x * v2.y - v2.x * v1.y;
  21. }
  22. function getRotateAngle(v1, v2) {
  23. var angle = getAngle(v1, v2);
  24. if (cross(v1, v2) > 0) {
  25. angle *= -1;
  26. }
  27. return angle * 180 / Math.PI;
  28. }
  29. var AlloyFinger = function (el, option) {
  30. this.element = typeof el == 'string' ? document.querySelector(el) : el;
  31. this.element.addEventListener("touchstart", this.start.bind(this), false);
  32. this.element.addEventListener("touchmove", this.move.bind(this), false);
  33. this.element.addEventListener("touchend", this.end.bind(this), false);
  34. this.element.addEventListener("touchcancel", this.cancel.bind(this), false);
  35. this.preV = { x: null, y: null };
  36. this.pinchStartLen = null;
  37. this.scale = 1;
  38. this.isDoubleTap = false;
  39. var noop = function () { };
  40. this.rotate = option.rotate || noop;
  41. this.touchStart = option.touchStart || noop;
  42. this.multipointStart = option.multipointStart || noop;
  43. this.multipointEnd = option.multipointEnd || noop;
  44. this.pinch = option.pinch || noop;
  45. this.swipe = option.swipe || noop;
  46. this.tap = option.tap || noop;
  47. this.doubleTap = option.doubleTap || noop;
  48. this.longTap = option.longTap || noop;
  49. this.singleTap = option.singleTap || noop;
  50. this.pressMove = option.pressMove || noop;
  51. this.touchMove = option.touchMove || noop;
  52. this.touchEnd = option.touchEnd || noop;
  53. this.touchCancel = option.touchCancel || noop;
  54. //add click
  55. this.click = option.click || noop;
  56. this.delta = null;
  57. this.last = null;
  58. this.now = null;
  59. this.tapTimeout = null;
  60. this.touchTimeout = null;
  61. this.longTapTimeout = null;
  62. this.swipeTimeout = null;
  63. this.x1 = this.x2 = this.y1 = this.y2 = null;
  64. this.preTapPosition = { x: null, y: null };
  65. };
  66. AlloyFinger.prototype = {
  67. start: function (evt) {
  68. if (!evt.touches) return;
  69. this.now = Date.now();
  70. this.x1 = evt.touches[0].pageX;
  71. this.y1 = evt.touches[0].pageY;
  72. this.delta = this.now - (this.last || this.now);
  73. this.touchStart(evt);
  74. if (this.preTapPosition.x !== null) {
  75. this.isDoubleTap = (this.delta > 0 && this.delta <= 250 && Math.abs(this.preTapPosition.x - this.x1) < 30 && Math.abs(this.preTapPosition.y - this.y1) < 30);
  76. }
  77. this.preTapPosition.x = this.x1;
  78. this.preTapPosition.y = this.y1;
  79. this.last = this.now;
  80. var preV = this.preV,
  81. len = evt.touches.length;
  82. if (len > 1) {
  83. this._cancelLongTap();
  84. var v = { x: evt.touches[1].pageX - this.x1, y: evt.touches[1].pageY - this.y1 };
  85. preV.x = v.x;
  86. preV.y = v.y;
  87. this.pinchStartLen = getLen(preV);
  88. this.multipointStart(evt);
  89. }
  90. this.longTapTimeout = setTimeout(function () {
  91. this.longTap(evt);
  92. }.bind(this), 750);
  93. },
  94. move: function (evt) {
  95. if (!evt.touches) return;
  96. var preV = this.preV,
  97. len = evt.touches.length,
  98. currentX = evt.touches[0].pageX,
  99. currentY = evt.touches[0].pageY;
  100. this.isDoubleTap = false;
  101. if (len > 1) {
  102. var v = { x: evt.touches[1].pageX - currentX, y: evt.touches[1].pageY - currentY };
  103. if (preV.x !== null) {
  104. if (this.pinchStartLen > 0) {
  105. evt.scale = getLen(v) / this.pinchStartLen;
  106. this.pinch(evt);
  107. }
  108. evt.angle = getRotateAngle(v, preV);
  109. this.rotate(evt);
  110. }
  111. preV.x = v.x;
  112. preV.y = v.y;
  113. } else {
  114. if (this.x2 !== null) {
  115. evt.deltaX = currentX - this.x2;
  116. evt.deltaY = currentY - this.y2;
  117. } else {
  118. evt.deltaX = 0;
  119. evt.deltaY = 0;
  120. }
  121. this.pressMove(evt);
  122. }
  123. this.touchMove(evt);
  124. this._cancelLongTap();
  125. this.x2 = currentX;
  126. this.y2 = currentY;
  127. if (evt.touches.length > 1) {
  128. this._cancelLongTap();
  129. evt.preventDefault();
  130. }
  131. },
  132. end: function (evt) {
  133. if (!evt.changedTouches) return;
  134. this._cancelLongTap();
  135. var self = this;
  136. if (evt.touches.length < 2) {
  137. this.multipointEnd(evt);
  138. }
  139. this.touchEnd(evt);
  140. //swipe
  141. if ((this.x2 && Math.abs(this.x1 - this.x2) > 30) ||
  142. (this.y2 && Math.abs(this.preV.y - this.y2) > 30)) {
  143. evt.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2);
  144. this.swipeTimeout = setTimeout(function () {
  145. self.swipe(evt);
  146. }, 0)
  147. } else {
  148. this.tapTimeout = setTimeout(function () {
  149. self.tap(evt);
  150. // trigger double tap immediately
  151. if (self.isDoubleTap) {
  152. self.doubleTap(evt);
  153. clearTimeout(self.touchTimeout);
  154. self.isDoubleTap = false;
  155. } else {
  156. self.touchTimeout = setTimeout(function () {
  157. self.singleTap(evt);
  158. }, 250);
  159. }
  160. }, 0)
  161. }
  162. this.preV.x = 0;
  163. this.preV.y = 0;
  164. this.scale = 1;
  165. this.pinchStartLen = null;
  166. this.x1 = this.x2 = this.y1 = this.y2 = null;
  167. },
  168. cancel: function (evt) {
  169. clearTimeout(this.touchTimeout);
  170. clearTimeout(this.tapTimeout);
  171. clearTimeout(this.longTapTimeout);
  172. clearTimeout(this.swipeTimeout);
  173. this.touchCancel(evt);
  174. },
  175. _cancelLongTap: function () {
  176. clearTimeout(this.longTapTimeout);
  177. },
  178. _swipeDirection: function (x1, x2, y1, y2) {
  179. return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
  180. }
  181. };
  182. if (typeof module !== 'undefined' && typeof exports === 'object') {
  183. module.exports = AlloyFinger;
  184. } else {
  185. window.AlloyFinger = AlloyFinger;
  186. }
  187. })();