gestureLock.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. class GestureLock {
  2. constructor(containerWidth, cycleRadius) {
  3. this.containerWidth = containerWidth; // 容器宽度
  4. this.cycleRadius = cycleRadius; // 圆的半径
  5. this.circleArray = []; // 全部圆的对象数组
  6. this.checkPoints = []; // 选中的圆的对象数组
  7. this.lineArray = []; // 已激活锁之间的线段数组
  8. this.lastCheckPoint = 0; // 最后一个激活的锁
  9. this.offsetX = 0; // 容器的 X 偏移
  10. this.offsetY = 0; // 容器的 Y 偏移
  11. this.activeLine = {}; // 最后一个激活的锁与当前位置之间的线段
  12. this.windowWidth = wx.getSystemInfoSync().windowWidth; // 窗口大小(用于rpx 和 px 转换)
  13. this.initCircleArray();
  14. }
  15. // 初始化 画布上的 9个圆
  16. initCircleArray() {
  17. const cycleMargin = (this.containerWidth - 6 * this.cycleRadius) / 6;
  18. let count = 0;
  19. for (let i = 0; i < 3; i++) {
  20. for (let j = 0; j < 3; j++) {
  21. count++;
  22. this.circleArray.push({
  23. count: count,
  24. x: this.rpxTopx((cycleMargin + this.cycleRadius) * (j * 2 + 1)),
  25. y: this.rpxTopx((cycleMargin + this.cycleRadius) * (i * 2 + 1)),
  26. radius: this.rpxTopx(this.cycleRadius),
  27. check: false,
  28. style: {
  29. left: (cycleMargin + this.cycleRadius) * (j * 2 + 1) - this.cycleRadius + 'rpx',
  30. top: (cycleMargin + this.cycleRadius) * (i * 2 + 1) - this.cycleRadius + 'rpx',
  31. width: this.cycleRadius * 2 + 'rpx',
  32. }
  33. });
  34. }
  35. }
  36. }
  37. onTouchStart(e) {
  38. this.setOffset(e);
  39. this.checkTouch({
  40. x: e.touches[0].pageX - this.offsetX,
  41. y: e.touches[0].pageY - this.offsetY
  42. });
  43. }
  44. onTouchMove(e) {
  45. this.moveDraw(e)
  46. }
  47. onTouchEnd(e) {
  48. const checkPoints = this.checkPoints;
  49. this.reset();
  50. return checkPoints;
  51. }
  52. // 初始化 偏移量
  53. setOffset(e) {
  54. this.offsetX = e.currentTarget.offsetLeft;
  55. this.offsetY = e.currentTarget.offsetTop;
  56. }
  57. // 检测当时 触摸位置是否位于 锁上
  58. checkTouch({
  59. x,
  60. y
  61. }) {
  62. for (let i = 0; i < this.circleArray.length; i++) {
  63. let point = this.circleArray[i];
  64. if (this.isPointInCycle(x, y, point.x, point.y, point.radius)) {
  65. if (!point.check) {
  66. this.checkPoints.push(point.count);
  67. if (this.lastCheckPoint != 0) {
  68. // 已激活锁之间的线段
  69. const line = this.drawLine(this.lastCheckPoint, point);
  70. this.lineArray.push(line);
  71. }
  72. this.lastCheckPoint = point;
  73. }
  74. point.check = true;
  75. return;
  76. }
  77. }
  78. }
  79. // 画线 - 返回 样式 对象
  80. drawLine(start, end) {
  81. const width = this.getPointDis(start.x, start.y, end.x, end.y);
  82. const rotate = this.getAngle(start, end);
  83. return {
  84. activeLeft: start.x + 'px',
  85. activeTop: start.y + 'px',
  86. activeWidth: width + 'px',
  87. activeRotate: rotate + 'deg'
  88. }
  89. }
  90. // 获取 画线的 角度
  91. getAngle(start, end) {
  92. var diff_x = end.x - start.x,
  93. diff_y = end.y - start.y;
  94. if (diff_x >= 0) {
  95. return 360 * Math.atan(diff_y / diff_x) / (2 * Math.PI);
  96. } else {
  97. return 180 + 360 * Math.atan(diff_y / diff_x) / (2 * Math.PI);
  98. }
  99. }
  100. // 判断 当前点是否位于 锁内
  101. isPointInCycle(x, y, circleX, circleY, radius) {
  102. return (this.getPointDis(x, y, circleX, circleY) < radius) ? true : false;
  103. }
  104. // 获取两点之间距离
  105. getPointDis(ax, ay, bx, by) {
  106. return Math.sqrt(Math.pow(ax - bx, 2) + Math.pow(ay - by, 2));
  107. }
  108. // 移动 绘制
  109. moveDraw(e) {
  110. // 画经过的圆
  111. const x = e.touches[0].pageX - this.offsetX;
  112. const y = e.touches[0].pageY - this.offsetY;
  113. this.checkTouch({
  114. x,
  115. y
  116. });
  117. // 画 最后一个激活的锁与当前位置之间的线段
  118. this.activeLine = this.drawLine(this.lastCheckPoint, {
  119. x,
  120. y
  121. });
  122. }
  123. // 使 画布 恢复初始状态
  124. reset() {
  125. this.circleArray.forEach((item) => {
  126. item.check = false;
  127. });
  128. this.checkPoints = [];
  129. this.lineArray = [];
  130. this.activeLine = {};
  131. this.lastCheckPoint = 0;
  132. }
  133. // 获取 最后一个激活的锁与当前位置之间的线段
  134. getActiveLine() {
  135. return this.activeLine;
  136. }
  137. // 获取 圆对象数组
  138. getCycleArray() {
  139. return this.circleArray;
  140. }
  141. // 获取 已激活锁之间的线段
  142. getLineArray() {
  143. return this.lineArray;
  144. }
  145. // 将 RPX 转换成 PX
  146. rpxTopx(rpx) {
  147. return rpx / 750 * this.windowWidth;
  148. }
  149. }
  150. export default GestureLock;