Prechádzať zdrojové kódy

缩小后弹性回复

MinJieLiu 7 rokov pred
rodič
commit
fa02405d1d

+ 43 - 7
src/PhotoView.tsx

@@ -8,7 +8,13 @@ import getMultipleTouchPosition from './utils/getMultipleTouchPosition';
 import getPositionOnMoveOrScale from './utils/getPositionOnMoveOrScale';
 import slideToSuitableOffset from './utils/slideToSuitableOffset';
 import { getClosedHorizontal, getClosedVertical } from './utils/getCloseEdge';
-import { defaultAnimationConfig, minReachOffset } from './variables';
+import {
+  defaultAnimationConfig,
+  minReachOffset,
+  minScale,
+  maxScale,
+  scaleBuffer,
+} from './variables';
 
 type ReachFunction = (pageX: number, pageY: number) => void;
 
@@ -81,7 +87,7 @@ export default class PhotoView extends React.Component<
 
   componentDidMount() {
     if (isMobile) {
-      window.addEventListener('touchmove', this.handleTouchMove);
+      window.addEventListener('touchmove', this.handleTouchMove, { passive: false });
       window.addEventListener('touchend', this.handleTouchEnd);
     } else {
       window.addEventListener('mousemove', this.handleMouseMove);
@@ -113,6 +119,7 @@ export default class PhotoView extends React.Component<
 
   handleMove = (newPageX: number, newPageY: number, touchLength: number = 0) => {
     if (this.state.touched) {
+      const { width, naturalWidth } = this.photoRef.state;
       this.setState(({
         x,
         y,
@@ -133,8 +140,15 @@ export default class PhotoView extends React.Component<
             return null;
           }
         }
-        const offsetScale = (touchLength - lastTouchLength) / 100 / 2 * scale;
-
+        const endScale = scale + (touchLength - lastTouchLength) / 100 / 2 * scale;
+        // 限制最大倍数和最小倍数
+        const toScale = Math.max(
+          Math.min(
+            endScale,
+            Math.max(maxScale, naturalWidth / width)
+          ),
+          minScale - scaleBuffer,
+        );
         return {
           lastTouchLength: touchLength,
           ...getPositionOnMoveOrScale({
@@ -143,7 +157,7 @@ export default class PhotoView extends React.Component<
             pageX: newPageX,
             pageY: newPageY,
             fromScale: scale,
-            toScale: scale + offsetScale,
+            toScale,
           }),
         };
       });
@@ -152,6 +166,7 @@ export default class PhotoView extends React.Component<
 
   handleDoubleClick = (e) => {
     const { pageX, pageY } = e;
+    const { width, naturalWidth } = this.photoRef.state;
     this.setState(({ x, y, scale }) => {
       return {
         pageX,
@@ -162,7 +177,8 @@ export default class PhotoView extends React.Component<
           pageX,
           pageY,
           fromScale: scale,
-          toScale: scale !== 1 ? 1 : 4,
+          // 若图片足够大,则放大适应的倍数
+          toScale: scale !== 1 ? 1 : Math.max(2, naturalWidth / width),
         }),
         animation: defaultAnimationConfig,
       };
@@ -171,7 +187,17 @@ export default class PhotoView extends React.Component<
 
   handleWheel = (e) => {
     const { pageX, pageY, deltaY } = e;
+    const { width, naturalWidth } = this.photoRef.state;
     this.setState(({ x, y, scale }) => {
+      const endScale = scale - deltaY / 100 / 2;
+      // 限制最大倍数和最小倍数
+      const toScale = Math.max(
+        Math.min(
+          endScale,
+          Math.max(maxScale, naturalWidth / width)
+        ),
+        minScale,
+      );
       return {
         pageX,
         pageY,
@@ -181,7 +207,7 @@ export default class PhotoView extends React.Component<
           pageX,
           pageY,
           fromScale: scale,
-          toScale: scale - deltaY / 100 / 2,
+          toScale,
         }),
         animation: defaultAnimationConfig,
       };
@@ -199,6 +225,7 @@ export default class PhotoView extends React.Component<
   }
 
   handleMouseDown = e => {
+    e.preventDefault();
     this.handleStart(e.pageX, e.pageY);
   }
 
@@ -236,8 +263,17 @@ export default class PhotoView extends React.Component<
           onReachUp(newPageX, newPageY);
         }
         const hasMove = pageX !== newPageX || pageY !== newPageY;
+        // 缩放弹性效果
+        const toScale = Math.max(
+          Math.min(
+            scale,
+            maxScale,
+          ),
+          minScale,
+        );
         return {
           touched: false,
+          scale: toScale,
           ...slideToSuitableOffset({
             x,
             y,

+ 1 - 1
src/utils/getMultipleTouchPosition.ts

@@ -1,7 +1,7 @@
 import React from 'react';
 
 /**
- * 从 Touch 事件中获取多个触控位置
+ * 从 Touch 事件中获取多个触控中心位置
  */
 const getMultipleTouchPosition = (
   evt: React.TouchEvent,

+ 11 - 21
src/utils/getPositionOnMoveOrScale.ts

@@ -21,31 +21,21 @@ const getPositionOnMoveOrScale = ({
   scale: number;
 } => {
   const { innerWidth, innerHeight } = window;
-  let endScale = toScale;
-  let originX = x;
-  let originY = y;
-  // 缩放限制
-  if (toScale < 1) {
-    endScale = 1;
-  } else if (toScale > 6) {
-    endScale = 6;
-  } else {
-    const centerPageX = innerWidth / 2;
-    const centerPageY = innerHeight / 2;
-    // 坐标偏移
-    const lastPositionX = centerPageX + x;
-    const lastPositionY = centerPageY + y;
+  const centerPageX = innerWidth / 2;
+  const centerPageY = innerHeight / 2;
+  // 坐标偏移
+  const lastPositionX = centerPageX + x;
+  const lastPositionY = centerPageY + y;
 
-    // 放大偏移量
-    const offsetScale = endScale / fromScale;
-    // 偏移位置
-    originX = pageX - (pageX - lastPositionX) * offsetScale - centerPageX;
-    originY = pageY - (pageY - lastPositionY) * offsetScale - centerPageY;
-  }
+  // 放大偏移量
+  const offsetScale = toScale / fromScale;
+  // 偏移位置
+  const originX = pageX - (pageX - lastPositionX) * offsetScale - centerPageX;
+  const originY = pageY - (pageY - lastPositionY) * offsetScale - centerPageY;
   return {
     x: originX,
     y: originY,
-    scale: endScale,
+    scale: toScale,
   };
 };
 

+ 18 - 3
src/variables.ts

@@ -6,17 +6,17 @@ import { springType } from './types';
 export const maxTouchTime: number = 200;
 
 /**
- * 最大切换滑动距离
+ * 最大滑动切换图片距离
  */
 export const maxMoveOffset: number = 40;
 
 /**
- * 最小触发边缘距离
+ * 最小触发边缘事件距离
  */
 export const minReachOffset: number = 40;
 
 /**
- * 关闭页面触发距离
+ * 下拉关闭页面触发距离
  */
 export const closePageOffset: number = 60;
 
@@ -26,6 +26,21 @@ export const closePageOffset: number = 60;
 export const defaultOpacity: number = 0.6;
 
 /**
+ * 最小缩放度
+ */
+export const minScale: number = 1;
+
+/**
+ * 最大缩放度(若图片足够大,则会被忽略)
+ */
+export const maxScale: number = 6;
+
+/**
+ * 缩放弹性缓冲
+ */
+export const scaleBuffer = 0.2;
+
+/**
  * 默认动画参数
  */
 export const defaultAnimationConfig: springType = {