utils.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { animationType } from './types';
  2. import { maxTouchTime, defaultAnimationConfig } from './variables';
  3. /**
  4. * 获取图片合适的大小
  5. * @param naturalWidth 图片真实宽度
  6. * @param naturalHeight 图片真实高度
  7. * @return 图片合适的大小
  8. */
  9. export const getSuitableImageSize = (
  10. naturalWidth: number,
  11. naturalHeight: number,
  12. ): {
  13. width: number;
  14. height: number;
  15. } => {
  16. let width = 0;
  17. let height = 0;
  18. const { innerWidth, innerHeight } = window;
  19. if (naturalWidth < innerWidth && naturalHeight < innerHeight) {
  20. width = naturalWidth;
  21. height = naturalHeight;
  22. } else if (naturalWidth < innerWidth && naturalHeight >= innerHeight) {
  23. width = (naturalWidth / naturalHeight) * innerHeight;
  24. height = innerHeight;
  25. } else if (naturalWidth >= innerWidth && naturalHeight < innerHeight) {
  26. width = innerWidth;
  27. height = (naturalHeight / naturalWidth) * innerWidth;
  28. } else if (
  29. naturalWidth >= innerWidth &&
  30. naturalHeight >= innerHeight &&
  31. naturalWidth / naturalHeight > innerWidth / innerHeight
  32. ) {
  33. width = innerWidth;
  34. height = (naturalHeight / naturalWidth) * innerWidth;
  35. } else {
  36. width = (naturalWidth / naturalHeight) * innerHeight;
  37. height = innerHeight;
  38. }
  39. return {
  40. width: Math.floor(width),
  41. height: Math.floor(height),
  42. };
  43. };
  44. export const getPositionOnScale = ({
  45. x,
  46. y,
  47. pageX,
  48. pageY,
  49. fromScale,
  50. toScale,
  51. }: {
  52. x: number;
  53. y: number;
  54. pageX: number;
  55. pageY: number;
  56. fromScale: number;
  57. toScale: number;
  58. }): {
  59. x: number;
  60. y: number;
  61. scale: number;
  62. } => {
  63. const { innerWidth, innerHeight } = window;
  64. let endScale = toScale;
  65. let distanceX = x;
  66. let distanceY = y;
  67. // 缩放限制
  68. if (toScale < 0.5) {
  69. endScale = 0.5;
  70. } else if (toScale > 5) {
  71. endScale = 5;
  72. } else {
  73. // 缩放距离计算
  74. const centerPageX = pageX - innerWidth / 2;
  75. const centerPageY = pageY - innerHeight / 2;
  76. const touchedImageX = (centerPageX - x) / fromScale;
  77. const touchedImageY = (centerPageY - y) / fromScale;
  78. const scale = endScale - fromScale;
  79. distanceX = x - centerPageX * scale;
  80. distanceY = y - centerPageY * scale;
  81. }
  82. return {
  83. x: distanceX,
  84. y: distanceY,
  85. scale: endScale,
  86. };
  87. };
  88. export const slideToPosition = ({
  89. x,
  90. y,
  91. lastX,
  92. lastY,
  93. touchedTime,
  94. }: {
  95. x: number;
  96. y: number;
  97. lastX: number;
  98. lastY: number;
  99. touchedTime: number;
  100. }): {
  101. endX: number;
  102. endY: number;
  103. } & animationType => {
  104. const moveTime = Date.now() - touchedTime;
  105. const speedX = (x - lastX) / moveTime;
  106. const speedY = (y - lastY) / moveTime;
  107. const maxSpeed = Math.max(speedX, speedY);
  108. const slideTime = moveTime < maxTouchTime ? Math.abs(maxSpeed) * 10 + 400 : 0;
  109. return {
  110. endX: Math.floor(x + speedX * slideTime),
  111. endY: Math.floor(y + speedY * slideTime),
  112. animation: {
  113. stiffness: 170,
  114. damping: 32,
  115. },
  116. };
  117. };
  118. /**
  119. * 跳转到合适的图片偏移量
  120. */
  121. export const jumpToSuitableOffset = ({
  122. x,
  123. y,
  124. lastX,
  125. lastY,
  126. width,
  127. height,
  128. scale,
  129. touchedTime,
  130. hasMove,
  131. }: {
  132. x: number;
  133. y: number;
  134. lastX: number;
  135. lastY: number;
  136. width: number;
  137. height: number;
  138. scale: number;
  139. touchedTime: number;
  140. hasMove: boolean;
  141. }): {
  142. x: number;
  143. y: number;
  144. } & animationType => {
  145. // 没有移动图片
  146. if (!hasMove) {
  147. return {
  148. x,
  149. y,
  150. animation: defaultAnimationConfig,
  151. };
  152. }
  153. const { innerWidth, innerHeight } = window;
  154. // 图片超出的长度
  155. const outOffsetX = (width * scale - innerWidth) / 2;
  156. const outOffsetY = (height * scale - innerHeight) / 2;
  157. // 滑动到结果的位置
  158. const { endX, endY, animation } = slideToPosition({ x, y, lastX, lastY, touchedTime });
  159. let currentX = endX;
  160. let currentY = endY;
  161. if (width * scale <= innerWidth) {
  162. currentX = 0;
  163. } else if (endX > 0 && outOffsetX - endX <= 0) {
  164. currentX = outOffsetX;
  165. } else if (endX < 0 && outOffsetX + endX <= 0) {
  166. currentX = -outOffsetX;
  167. }
  168. if (height * scale <= innerHeight) {
  169. currentY = 0;
  170. } else if (endY > 0 && outOffsetY - endY <= 0) {
  171. currentY = outOffsetY;
  172. } else if (endY < 0 && outOffsetY + endY <= 0) {
  173. currentY = -outOffsetY;
  174. }
  175. const isSlide = currentX === endX || currentY === endY;
  176. return {
  177. x: currentX,
  178. y: currentY,
  179. animation: isSlide ? defaultAnimationConfig : animation,
  180. };
  181. };