Browse Source

中心点优化

MinJieLiu 7 years ago
parent
commit
437ff81e7d
2 changed files with 88 additions and 45 deletions
  1. 44 27
      src/PhotoView.tsx
  2. 44 18
      src/utils.ts

+ 44 - 27
src/PhotoView.tsx

@@ -25,9 +25,13 @@ type PhotoViewState = {
   // 触摸开始时 y 原始坐标
   pageY: number;
   // 触摸开始时图片 x 偏移量
-  offsetX: number;
+  lastX: number;
   // 触摸开始时图片 y 偏移量
-  offsetY: number;
+  lastY: number;
+  // 上一次触摸开始时 x 原始坐标
+  lastPageX: number | undefined;
+  // 上一次触摸开始时 y 原始坐标
+  lastPageY: number | undefined;
   // 触摸开始时时间
   touchedTime: number;
 } & animationType;
@@ -46,8 +50,12 @@ export default class PhotoView extends React.Component<
 
     pageX: 0,
     pageY: 0,
-    offsetX: 0,
-    offsetY: 0,
+
+    lastX: 0,
+    lastY: 0,
+
+    lastPageX: undefined,
+    lastPageY: undefined,
     touchedTime: 0,
 
     animation: defaultAnimationConfig,
@@ -80,18 +88,18 @@ export default class PhotoView extends React.Component<
       touched: true,
       pageX,
       pageY,
-      offsetX: prevState.x,
-      offsetY: prevState.y,
+      lastX: prevState.x,
+      lastY: prevState.y,
       touchedTime: Date.now(),
     }));
   }
 
   handleMove = (newPageX, newPageY) => {
     if (this.state.touched) {
-      this.setState(({ pageX, pageY, offsetX, offsetY }) => {
+      this.setState(({ pageX, pageY, lastX, lastY }) => {
         return {
-          x: newPageX - pageX + offsetX,
-          y: newPageY - pageY + offsetY,
+          x: newPageX - pageX + lastX,
+          y: newPageY - pageY + lastY,
         };
       });
     }
@@ -99,31 +107,40 @@ export default class PhotoView extends React.Component<
 
   handleDoubleClick = (e) => {
     const { pageX, pageY } = e;
-    this.setState(({ x, y, scale }) => {
-      const toScale = scale > 1 ? 1 : 4;
-      const { distanceX, distanceY } = getPositionOnScale({ x, y, pageX, pageY, toScale });
+    this.setState(({ x, y, scale, lastPageX, lastPageY }) => {
       return {
-        x: distanceX,
-        y: distanceY,
         pageX,
         pageY,
-        scale: toScale,
+        ...getPositionOnScale({
+          x,
+          y,
+          pageX,
+          pageY,
+          lastPageX,
+          lastPageY,
+          fromScale: scale,
+          toScale: scale > 1 ? 1 : 2,
+        }),
       };
     });
   }
 
   handleWheel = (e) => {
     const { pageX, pageY, deltaY } = e;
-    this.setState(({ x, y, scale }) => {
-      const toScale = scale + deltaY / 100;
-      const { distanceX, distanceY } = getPositionOnScale({ x, y, pageX, pageY, toScale });
-
+    this.setState(({ x, y, scale, lastPageX, lastPageY }) => {
       return {
-        x: distanceX,
-        y: distanceY,
         pageX,
         pageY,
-        scale: toScale,
+        ...getPositionOnScale({
+          x,
+          y,
+          pageX,
+          pageY,
+          lastPageX,
+          lastPageY,
+          fromScale: scale,
+          toScale: scale - deltaY / 100 / 2,
+        }),
         animation: defaultAnimationConfig,
       };
     });
@@ -153,20 +170,20 @@ export default class PhotoView extends React.Component<
     this.setState(({
       x,
       y,
-      offsetX,
-      offsetY,
+      lastX,
+      lastY,
       scale,
       touchedTime,
       ...restPrevState
     }) => {
-      const hasMove: boolean = pageX !== restPrevState.pageX || pageY !== restPrevState.pageY;
+      const hasMove = pageX !== restPrevState.pageX || pageY !== restPrevState.pageY;
       return {
         touched: false,
         ...jumpToSuitableOffset({
           x,
           y,
-          offsetX,
-          offsetY,
+          lastX,
+          lastY,
           width,
           height,
           scale,

+ 44 - 18
src/utils.ts

@@ -48,46 +48,72 @@ export const getPositionOnScale = ({
   y,
   pageX,
   pageY,
+  lastPageX,
+  lastPageY,
+  fromScale,
   toScale,
 }: {
   x: number;
   y: number;
   pageX: number;
   pageY: number;
+  lastPageX: number | undefined;
+  lastPageY: number | undefined;
+  fromScale: number;
   toScale: number;
 }): {
-  distanceX: number;
-  distanceY: number;
+  x: number;
+  y: number;
+  lastPageX: number;
+  lastPageY: number;
+  scale: number;
 } => {
   const { innerWidth, innerHeight } = window;
-  const scale = toScale - 1;
-  const distanceX = (innerWidth / 2 - x - pageX) * scale;
-  const distanceY = (innerHeight / 2 - y - pageY) * scale;
+  let endScale = toScale;
+  let distanceX = x;
+  let distanceY = y;
+  // 缩放限制
+  if (toScale < 0.5) {
+    endScale = 0.5;
+  } else if (toScale > 5) {
+    endScale = 5;
+  } else {
+    // 缩放距离计算
+    const centerPageX = pageX - innerWidth / 2;
+    const centerPageY = pageY - innerHeight / 2;
+    const scale = endScale - fromScale;
+
+    distanceX = x - centerPageX * scale;
+    distanceY = y - centerPageY * scale;
+  }
   return {
-    distanceX: Math.floor(distanceX),
-    distanceY: Math.floor(distanceY),
+    x: distanceX,
+    y: distanceY,
+    lastPageX: pageX,
+    lastPageY: pageY,
+    scale: endScale,
   };
 };
 
 export const slideToPosition = ({
   x,
   y,
-  offsetX,
-  offsetY,
+  lastX,
+  lastY,
   touchedTime,
 }: {
   x: number;
   y: number;
-  offsetX: number;
-  offsetY: number;
+  lastX: number;
+  lastY: number;
   touchedTime: number;
 }): {
   endX: number;
   endY: number;
 } & animationType => {
   const moveTime = Date.now() - touchedTime;
-  const speedX = (x - offsetX) / moveTime;
-  const speedY = (y - offsetY) / moveTime;
+  const speedX = (x - lastX) / moveTime;
+  const speedY = (y - lastY) / moveTime;
   const maxSpeed = Math.max(speedX, speedY);
   const slideTime = moveTime < maxTouchTime ? Math.abs(maxSpeed) * 10 + 400 : 0;
   return {
@@ -106,8 +132,8 @@ export const slideToPosition = ({
 export const jumpToSuitableOffset = ({
   x,
   y,
-  offsetX,
-  offsetY,
+  lastX,
+  lastY,
   width,
   height,
   scale,
@@ -116,8 +142,8 @@ export const jumpToSuitableOffset = ({
 }: {
   x: number;
   y: number;
-  offsetX: number;
-  offsetY: number;
+  lastX: number;
+  lastY: number;
   width: number;
   height: number;
   scale: number;
@@ -142,7 +168,7 @@ export const jumpToSuitableOffset = ({
   const outOffsetY = (height * scale - innerHeight) / 2;
 
   // 滑动到结果的位置
-  const { endX, endY, animation } = slideToPosition({ x, y, offsetX, offsetY, touchedTime });
+  const { endX, endY, animation } = slideToPosition({ x, y, lastX, lastY, touchedTime });
 
   let currentX = endX;
   let currentY = endY;