Bladeren bron

触控放大

MinJieLiu 7 jaren geleden
bovenliggende
commit
5791a5d500
2 gewijzigde bestanden met toevoegingen van 53 en 32 verwijderingen
  1. 32 21
      src/PhotoView.tsx
  2. 21 11
      src/utils.ts

+ 32 - 21
src/PhotoView.tsx

@@ -5,8 +5,8 @@ import Photo from './Photo';
 import { PhotoContainer, Backdrop } from './StyledElements';
 import {
   isMobile,
-  getTouchCenter,
-  getPositionOnScale,
+  getMultipleTouchPosition,
+  getPositionOnMoveOrScale,
   jumpToSuitableOffset,
 } from './utils';
 import { defaultAnimationConfig } from './variables';
@@ -33,6 +33,8 @@ type PhotoViewState = {
   lastX: number;
   // 触摸开始时图片 y 偏移量
   lastY: number;
+  // 两指间距
+  lastTouchLength: number;
 
   // 触摸开始时时间
   touchedTime: number;
@@ -62,6 +64,7 @@ export default class PhotoView extends React.Component<
     originTranslateY: 0,
 
     touchedTime: 0,
+    lastTouchLength: 0,
     animation: defaultAnimationConfig,
   };
 
@@ -92,23 +95,31 @@ export default class PhotoView extends React.Component<
     }
   }
 
-  handleStart = (pageX, pageY) => {
+  handleStart = (pageX: number, pageY: number, touchLength: number = 0) => {
     this.setState(prevState => ({
       touched: true,
       pageX,
       pageY,
       lastX: prevState.x,
       lastY: prevState.y,
+      lastTouchLength: touchLength,
       touchedTime: Date.now(),
     }));
   }
 
-  handleMove = (newPageX, newPageY) => {
+  handleMove = (newPageX: number, newPageY: number, touchLength: number = 0) => {
     if (this.state.touched) {
-      this.setState(({ pageX, pageY, lastX, lastY }) => {
+      this.setState(({ pageX, pageY, lastX, lastY, scale, lastTouchLength }) => {
         return {
-          x: newPageX - pageX + lastX,
-          y: newPageY - pageY + lastY,
+          lastTouchLength: touchLength,
+          ...getPositionOnMoveOrScale({
+            x: newPageX - pageX + lastX,
+            y: newPageY - pageY + lastY,
+            pageX,
+            pageY,
+            fromScale: scale,
+            toScale: scale + (touchLength - lastTouchLength) * 4 / window.innerWidth,
+          }),
         };
       });
     }
@@ -120,13 +131,13 @@ export default class PhotoView extends React.Component<
       return {
         pageX,
         pageY,
-        ...getPositionOnScale({
+        ...getPositionOnMoveOrScale({
           x,
           y,
           pageX,
           pageY,
           fromScale: scale,
-          toScale: scale < 4 ? scale * 2 : 1,
+          toScale: scale !== 1 ? 1 : 2,
         }),
         animation: defaultAnimationConfig,
       };
@@ -139,7 +150,7 @@ export default class PhotoView extends React.Component<
       return {
         pageX,
         pageY,
-        ...getPositionOnScale({
+        ...getPositionOnMoveOrScale({
           x,
           y,
           pageX,
@@ -153,10 +164,10 @@ export default class PhotoView extends React.Component<
   }
 
   handleTouchStart = e => {
-    const { pageX, pageY } = e.touches.length >= 2
-      ? getTouchCenter(e)
+    const { pageX, pageY, touchLength } = e.touches.length >= 2
+      ? getMultipleTouchPosition(e)
       : e.touches[0];
-    this.handleStart(pageX, pageY);
+    this.handleStart(pageX, pageY, touchLength);
   }
 
   handleMouseDown = e => {
@@ -165,10 +176,10 @@ export default class PhotoView extends React.Component<
 
   handleTouchMove = e => {
     e.preventDefault();
-    const { pageX, pageY } = e.touches.length >= 2
-      ? getTouchCenter(e)
+    const { pageX, pageY, touchLength } = e.touches.length >= 2
+      ? getMultipleTouchPosition(e)
       : e.touches[0];
-    this.handleMove(pageX, pageY);
+    this.handleMove(pageX, pageY, touchLength);
   }
 
   handleMouseMove = e => {
@@ -176,7 +187,7 @@ export default class PhotoView extends React.Component<
     this.handleMove(e.pageX, e.pageY);
   }
 
-  handleUp = (pageX, pageY) => {
+  handleUp = (newPageX: number, newPageY: number) => {
     const { width, height } = this.photoRef.state;
     this.setState(({
       x,
@@ -185,10 +196,10 @@ export default class PhotoView extends React.Component<
       lastY,
       scale,
       touchedTime,
-      ...restPrevState
+      pageX,
+      pageY,
     }) => {
-      const hasMove = pageX !== restPrevState.pageX
-        || pageY !== restPrevState.pageY;
+      const hasMove = pageX !== newPageX || pageY !== newPageY;
       return {
         touched: false,
         ...jumpToSuitableOffset({
@@ -226,7 +237,7 @@ export default class PhotoView extends React.Component<
     const style = {
       currX: touched ? x : spring(x, animation),
       currY: touched ? y : spring(y, animation),
-      currScale: spring(scale, animation),
+      currScale: touched ? scale : spring(scale, animation),
     };
 
     return (

+ 21 - 11
src/utils.ts

@@ -8,19 +8,23 @@ import { maxTouchTime, defaultAnimationConfig } from './variables';
 export const isMobile: boolean = window.navigator.userAgent.includes('Mobile');
 
 /**
- * 从 Touch 事件中获取双指中心点
+ * 从 Touch 事件中获取多个触控位置
  */
-export const getTouchCenter = (evt: React.TouchEvent): {
+export const getMultipleTouchPosition = (
+  evt: React.TouchEvent,
+): {
   pageX: number;
   pageY: number;
+  touchLength: number;
 } => {
-  const firstTouch = evt.touches[0];
-  const secondTouch = evt.touches[1];
-  const pageX = (firstTouch.pageX + secondTouch.pageX) / 2;
-  const pageY = (firstTouch.pageY + secondTouch.pageY) / 2;
+  const { pageX, pageY } = evt.touches[0];
+  const { pageX: nextPageX, pageY: nextPageY } = evt.touches[1];
   return {
-    pageX,
-    pageY,
+    pageX: (pageX + nextPageX) / 2,
+    pageY: (pageY + nextPageY) / 2,
+    touchLength: Math.sqrt(
+      Math.pow(nextPageX - pageX, 2) + Math.pow(nextPageY - pageY, 2),
+    ),
   };
 };
 
@@ -66,7 +70,7 @@ export const getSuitableImageSize = (
   };
 };
 
-export const getPositionOnScale = ({
+export const getPositionOnMoveOrScale = ({
   x,
   y,
   pageX,
@@ -94,7 +98,7 @@ export const getPositionOnScale = ({
     endScale = 0.5;
   } else if (toScale > 5) {
     endScale = 5;
-  } else {
+  } else if (toScale - fromScale !== 0) { // 有缩放的情况下
     const centerPageX = innerWidth / 2;
     const centerPageY = innerHeight / 2;
     // 坐标偏移
@@ -185,7 +189,13 @@ export const jumpToSuitableOffset = ({
   const outOffsetY = (height * scale - innerHeight) / 2;
 
   // 滑动到结果的位置
-  const { endX, endY, animation } = slideToPosition({ x, y, lastX, lastY, touchedTime });
+  const { endX, endY, animation } = slideToPosition({
+    x,
+    y,
+    lastX,
+    lastY,
+    touchedTime,
+  });
 
   let currentX = endX;
   let currentY = endY;