feat: support pdf zoom in mobile (#990)

Reviewed-on: daoyoucloud/tachybase#990
This commit is contained in:
sealday 2024-05-15 20:24:06 +08:00
parent 04a6f3f09a
commit d0bb8038ab
5 changed files with 71 additions and 25 deletions

View File

@ -36,6 +36,7 @@
"react-pdf": "^7.5.1", "react-pdf": "^7.5.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-transition-group": "^4.4.5", "react-transition-group": "^4.4.5",
"react-zoom-pan-pinch": "^3.4.4",
"redis": "^4.6.11", "redis": "^4.6.11",
"signature_pad": "4.1.7", "signature_pad": "4.1.7",
"throttle-debounce": "^5.0.0", "throttle-debounce": "^5.0.0",

View File

@ -1,13 +1,14 @@
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import { Spin } from 'antd'; import { Spin, Tag } from 'antd';
import { LoadingOutlined } from '@ant-design/icons'; import { LoadingOutlined } from '@ant-design/icons';
import { Document, Page, pdfjs } from 'react-pdf'; import { Document, Page, pdfjs } from 'react-pdf';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import 'react-pdf/dist/Page/AnnotationLayer.css'; import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css'; import 'react-pdf/dist/Page/TextLayer.css';
import { uid } from '@tachybase/schema'; import { uid } from '@tachybase/schema';
import { useRequest } from '@tachybase/client'; import { css, useRequest } from '@tachybase/client';
import { useTranslation } from '../locale'; import { useTranslation } from '../locale';
import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';
const options = { const options = {
cMapUrl: '/cmaps/', cMapUrl: '/cmaps/',
@ -79,28 +80,48 @@ export const PDFViewer = forwardRef<PDFViewerRef, PDFViewerProps>((props, ref) =
return ( return (
<LoadingSpin spinning={loading}> <LoadingSpin spinning={loading}>
<Document <TransformWrapper
options={options} wheel={{ disabled: true }}
file={data as ArrayBuffer} doubleClick={{ disabled: true }}
loading={() => ( panning={{ allowLeftClickPan: false }}
<LoadingSpin spinning={true}>
<div style={{ height: '100vh' }}></div>
</LoadingSpin>
)}
onLoadSuccess={async (doc) => {
setNumPages(doc.numPages);
}}
noData={<div style={{ height: '100vh' }}></div>}
error={<div>{t('error')}</div>}
> >
{Array.from(new Array(numPages), (el, index) => ( <TransformComponent>
<Page key={`page_${index + 1}`} pageNumber={index + 1} width={width}> <Document
<p style={{ marginLeft: '92%', marginBottom: '30pt', fontSize: '14px', fontFamily: 'source-han-sans' }}> options={options}
{index + 1}/{numPages} file={data as ArrayBuffer}
</p> loading={() => (
</Page> <LoadingSpin spinning={true}>
))} <div style={{ height: '100vh' }}></div>
</Document> </LoadingSpin>
)}
onLoadSuccess={async (doc) => {
setNumPages(doc.numPages);
}}
noData={<div style={{ height: '100vh' }}></div>}
error={<div>{t('error')}</div>}
>
{Array.from(new Array(numPages), (el, index) => (
<Page key={`page_${index + 1}`} pageNumber={index + 1} width={width}>
<div
className={css`
text-align: center;
border-bottom: 1px dashed;
`}
>
<Tag
className={css`
margin-bottom: 2px;
`}
bordered={false}
>
{index + 1}/{numPages}
</Tag>
</div>
</Page>
))}
</Document>
</TransformComponent>
</TransformWrapper>
</LoadingSpin> </LoadingSpin>
); );
}); });

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Plugin, EditTitleField } from '@tachybase/client'; import { Plugin, EditTitleField, CollectionProvider, CollectionRecordProvider } from '@tachybase/client';
import { useFieldSchema } from '@tachybase/schema'; import { useFieldSchema } from '@tachybase/schema';
import { isValid } from '@tachybase/schema'; import { isValid } from '@tachybase/schema';
import { autorun } from '@tachybase/schema'; import { autorun } from '@tachybase/schema';

View File

@ -3,6 +3,7 @@ import { PDFViewer } from '../../components/PDFViewer';
import { Space } from 'antd'; import { Space } from 'antd';
import { css } from '@tachybase/client'; import { css } from '@tachybase/client';
import { usePDFViewerRef } from '../../schema-initializer/blocks/PDFVIewerBlockInitializer'; import { usePDFViewerRef } from '../../schema-initializer/blocks/PDFVIewerBlockInitializer';
import { debounce } from 'lodash';
export const InternalPDFViewer = (props) => { export const InternalPDFViewer = (props) => {
const { usePdfPath: useMaybePdfPath } = props; const { usePdfPath: useMaybePdfPath } = props;
@ -10,10 +11,19 @@ export const InternalPDFViewer = (props) => {
const [width, setWidth] = useState(0); const [width, setWidth] = useState(0);
const [, setHeight] = useState(0); const [, setHeight] = useState(0);
useEffect(() => { useEffect(() => {
if (containerRef.current) { const updateUI = debounce(() => {
setWidth(containerRef.current.offsetWidth); setWidth(containerRef.current.offsetWidth);
setHeight(containerRef.current.offsetHeight); setHeight(containerRef.current.offsetHeight);
}, 200);
const observer = new ResizeObserver(() => {
updateUI();
});
if (containerRef.current) {
observer.observe(containerRef.current);
} }
return () => {
observer.disconnect();
};
}, [containerRef]); }, [containerRef]);
const ref = usePDFViewerRef(); const ref = usePDFViewerRef();
const usePdfPath = useMaybePdfPath ?? (() => ''); const usePdfPath = useMaybePdfPath ?? (() => '');

View File

@ -1610,6 +1610,9 @@ importers:
react-transition-group: react-transition-group:
specifier: ^4.4.5 specifier: ^4.4.5
version: 4.4.5(react-dom@18.2.0)(react@18.2.0) version: 4.4.5(react-dom@18.2.0)(react@18.2.0)
react-zoom-pan-pinch:
specifier: ^3.4.4
version: 3.4.4(react-dom@18.2.0)(react@18.2.0)
redis: redis:
specifier: ^4.6.11 specifier: ^4.6.11
version: 4.6.13 version: 4.6.13
@ -26700,6 +26703,17 @@ packages:
react-dom: 18.2.0(react@18.2.0) react-dom: 18.2.0(react@18.2.0)
dev: true dev: true
/react-zoom-pan-pinch@3.4.4(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-lGTu7D9lQpYEQ6sH+NSlLA7gicgKRW8j+D/4HO1AbSV2POvKRFzdWQ8eI0r3xmOsl4dYQcY+teV6MhULeg1xBw==}
engines: {node: '>=8', npm: '>=5'}
peerDependencies:
react: '*'
react-dom: '*'
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: true
/react@18.1.0: /react@18.1.0:
resolution: {integrity: sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==} resolution: {integrity: sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}