Browse Source

add zoom in/out with gesture

RoyLiu 4 years ago
parent
commit
938edfb638
5 changed files with 474 additions and 304 deletions
  1. 31 2
      containers/PdfPages.tsx
  2. 4 1
      custom.d.ts
  3. 37 0
      hooks/useGestureScale.ts
  4. 1 0
      package.json
  5. 401 301
      yarn.lock

+ 31 - 2
containers/PdfPages.tsx

@@ -3,20 +3,35 @@ import _ from 'lodash';
 
 import Viewer from '../components/Viewer';
 import PdfPage from './PdfPage';
-import { watchScroll } from '../helpers/utility';
+import { watchScroll, scaleCheck } from '../helpers/utility';
+import useGestureScale from '../hooks/useGestureScale';
 
+import useActions from '../actions';
 import useStore from '../store';
 
 type Props = {
   scrollToUpdate: (state: ScrollStateType) => void;
 };
 
+let timer = 0;
+
 const PdfPages: React.FC<Props> = ({ scrollToUpdate }: Props) => {
   const [elements, setElement] = useState<React.ReactNode[]>([]);
   const containerRef = useRef<HTMLDivElement>(null);
   const [
-    { totalPage, currentPage, viewport, rotation, displayMode, annotations },
+    {
+      totalPage,
+      currentPage,
+      scale,
+      viewport,
+      rotation,
+      displayMode,
+      annotations,
+    },
+    dispatch,
   ] = useStore();
+  const { changeScale } = useActions(dispatch);
+  const [zoom] = useGestureScale(containerRef);
 
   const createPages = (): void => {
     const pagesContent: React.ReactNode[] = [];
@@ -76,6 +91,20 @@ const PdfPages: React.FC<Props> = ({ scrollToUpdate }: Props) => {
     updatePages();
   }, [currentPage, viewport, rotation, annotations]);
 
+  useEffect(() => {
+    if (zoom !== 0) {
+      const viewer = containerRef.current as HTMLElement;
+      viewer.style.transform = `scale(${1 + zoom})`;
+      clearTimeout(timer);
+
+      timer = setTimeout(() => {
+        const targetScale = Math.round(scale * 100 + zoom * 100);
+        changeScale(scaleCheck(targetScale));
+        viewer.style.transform = `scale(1)`;
+      }, 500);
+    }
+  }, [zoom]);
+
   return (
     <Viewer
       ref={containerRef}

+ 4 - 1
custom.d.ts

@@ -4,12 +4,15 @@ declare module '*.svg' {
 }
 
 declare module 'pdfjs-dist';
-declare module 'pdfjs-dist/build/pdf.worker.entry';
 declare module 'query-string';
 declare module 'react-toast-notifications';
 declare module 'react-color';
 declare module 'react-color/lib/components/common';
 
+interface RefObject<T> {
+  readonly current: T | null;
+}
+
 type SelectOptionType = {
   key: string | number;
   content: React.ReactNode;

+ 37 - 0
hooks/useGestureScale.ts

@@ -0,0 +1,37 @@
+import { useEffect, useState } from 'react';
+import { usePinch } from 'react-use-gesture';
+
+const useGestureScale = (domTarget: RefObject<HTMLDivElement> | null) => {
+  const [zoom, set] = useState(0);
+
+  const bind = usePinch(
+    ({ offset: [d] }) => {
+      set(d / 200);
+    },
+    {
+      domTarget,
+      eventOptions: { passive: false },
+      distanceBounds: { min: -100, max: 150 },
+    }
+  );
+
+  const notAllowOriginalEvent = (e: any) => e.preventDefault();
+
+  useEffect(() => {
+    document.addEventListener('gesturestart', notAllowOriginalEvent);
+    document.addEventListener('gesturechange', notAllowOriginalEvent);
+
+    return () => {
+      document.removeEventListener('gesturestart', notAllowOriginalEvent);
+      document.removeEventListener('gesturechange', notAllowOriginalEvent);
+    };
+  }, []);
+
+  useEffect(() => {
+    bind();
+  }, [bind]);
+
+  return [zoom];
+};
+
+export default useGestureScale;

+ 1 - 0
package.json

@@ -30,6 +30,7 @@
     "react-i18next": "^11.3.4",
     "react-popper": "^1.3.6",
     "react-toast-notifications": "^2.4.0",
+    "react-use-gesture": "^7.0.16",
     "rxjs": "^6.5.3",
     "styled-components": "5.1.1",
     "uuid": "^7.0.2",

File diff suppressed because it is too large
+ 401 - 301
yarn.lock