* fix: by obtaining the width and height of the pdf and passing it to boundingRect, the problem of inaccurate positioning of file highlighting is fixed * feat: remove actualPositions from buildChunkHighlightstags/v0.1.0
| @@ -35,7 +35,7 @@ const HighlightPopup = ({ | |||
| const DocumentPreviewer = ({ chunk, documentId, visible }: IProps) => { | |||
| const url = useGetDocumentUrl(documentId); | |||
| const state = useGetChunkHighlights(chunk); | |||
| const { highlights: state, setWidthAndHeight } = useGetChunkHighlights(chunk); | |||
| const ref = useRef<(highlight: IHighlight) => void>(() => {}); | |||
| const [loaded, setLoaded] = useState(false); | |||
| @@ -59,59 +59,68 @@ const DocumentPreviewer = ({ chunk, documentId, visible }: IProps) => { | |||
| beforeLoad={<Skeleton active />} | |||
| workerSrc="/pdfjs-dist/pdf.worker.min.js" | |||
| > | |||
| {(pdfDocument) => ( | |||
| <PdfHighlighter | |||
| pdfDocument={pdfDocument} | |||
| enableAreaSelection={(event) => event.altKey} | |||
| onScrollChange={resetHash} | |||
| scrollRef={(scrollTo) => { | |||
| ref.current = scrollTo; | |||
| setLoaded(true); | |||
| }} | |||
| onSelectionFinished={() => null} | |||
| highlightTransform={( | |||
| highlight, | |||
| index, | |||
| setTip, | |||
| hideTip, | |||
| viewportToScaled, | |||
| screenshot, | |||
| isScrolledTo, | |||
| ) => { | |||
| const isTextHighlight = !Boolean( | |||
| highlight.content && highlight.content.image, | |||
| ); | |||
| {(pdfDocument) => { | |||
| pdfDocument.getPage(1).then((page) => { | |||
| const viewport = page.getViewport({ scale: 1 }); | |||
| const width = viewport.width; | |||
| const height = viewport.height; | |||
| setWidthAndHeight(width, height); | |||
| }); | |||
| const component = isTextHighlight ? ( | |||
| <Highlight | |||
| isScrolledTo={isScrolledTo} | |||
| position={highlight.position} | |||
| comment={highlight.comment} | |||
| /> | |||
| ) : ( | |||
| <AreaHighlight | |||
| isScrolledTo={isScrolledTo} | |||
| highlight={highlight} | |||
| onChange={() => {}} | |||
| /> | |||
| ); | |||
| return ( | |||
| <PdfHighlighter | |||
| pdfDocument={pdfDocument} | |||
| enableAreaSelection={(event) => event.altKey} | |||
| onScrollChange={resetHash} | |||
| scrollRef={(scrollTo) => { | |||
| ref.current = scrollTo; | |||
| setLoaded(true); | |||
| }} | |||
| onSelectionFinished={() => null} | |||
| highlightTransform={( | |||
| highlight, | |||
| index, | |||
| setTip, | |||
| hideTip, | |||
| viewportToScaled, | |||
| screenshot, | |||
| isScrolledTo, | |||
| ) => { | |||
| const isTextHighlight = !Boolean( | |||
| highlight.content && highlight.content.image, | |||
| ); | |||
| return ( | |||
| <Popup | |||
| popupContent={<HighlightPopup {...highlight} />} | |||
| onMouseOver={(popupContent) => | |||
| setTip(highlight, () => popupContent) | |||
| } | |||
| onMouseOut={hideTip} | |||
| key={index} | |||
| > | |||
| {component} | |||
| </Popup> | |||
| ); | |||
| }} | |||
| highlights={state} | |||
| /> | |||
| )} | |||
| const component = isTextHighlight ? ( | |||
| <Highlight | |||
| isScrolledTo={isScrolledTo} | |||
| position={highlight.position} | |||
| comment={highlight.comment} | |||
| /> | |||
| ) : ( | |||
| <AreaHighlight | |||
| isScrolledTo={isScrolledTo} | |||
| highlight={highlight} | |||
| onChange={() => {}} | |||
| /> | |||
| ); | |||
| return ( | |||
| <Popup | |||
| popupContent={<HighlightPopup {...highlight} />} | |||
| onMouseOver={(popupContent) => | |||
| setTip(highlight, () => popupContent) | |||
| } | |||
| onMouseOut={hideTip} | |||
| key={index} | |||
| > | |||
| {component} | |||
| </Popup> | |||
| ); | |||
| }} | |||
| highlights={state} | |||
| /> | |||
| ); | |||
| }} | |||
| </PdfLoader> | |||
| </div> | |||
| ); | |||
| @@ -2,7 +2,7 @@ import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||
| import { api_host } from '@/utils/api'; | |||
| import { buildChunkHighlights } from '@/utils/documentUtils'; | |||
| import { useCallback, useMemo } from 'react'; | |||
| import { useCallback, useMemo, useState } from 'react'; | |||
| import { IHighlight } from 'react-pdf-highlighter'; | |||
| import { useDispatch, useSelector } from 'umi'; | |||
| import { useGetKnowledgeSearchParams } from './routeHook'; | |||
| @@ -15,12 +15,23 @@ export const useGetDocumentUrl = (documentId: string) => { | |||
| return url; | |||
| }; | |||
| export const useGetChunkHighlights = (selectedChunk: IChunk): IHighlight[] => { | |||
| export const useGetChunkHighlights = (selectedChunk: IChunk) => { | |||
| const [size, setSize] = useState({ width: 849, height: 1200 }); | |||
| const highlights: IHighlight[] = useMemo(() => { | |||
| return buildChunkHighlights(selectedChunk); | |||
| }, [selectedChunk]); | |||
| return buildChunkHighlights(selectedChunk, size); | |||
| }, [selectedChunk, size]); | |||
| const setWidthAndHeight = (width: number, height: number) => { | |||
| setSize((pre) => { | |||
| if (pre.height !== height || pre.width !== width) { | |||
| return { height, width }; | |||
| } | |||
| return pre; | |||
| }); | |||
| }; | |||
| return highlights; | |||
| return { highlights, setWidthAndHeight }; | |||
| }; | |||
| export const useFetchDocumentList = () => { | |||
| @@ -9,11 +9,11 @@ | |||
| caption { | |||
| color: @blurBackground; | |||
| font-size: 20px; | |||
| height: 50px; | |||
| line-height: 50px; | |||
| font-size: 14px; | |||
| height: 20px; | |||
| line-height: 20px; | |||
| font-weight: 600; | |||
| margin-bottom: 10px; | |||
| margin-bottom: 6px; | |||
| } | |||
| th { | |||
| @@ -30,7 +30,8 @@ const HighlightPopup = ({ | |||
| // TODO: merge with DocumentPreviewer | |||
| const Preview = ({ selectedChunkId }: IProps) => { | |||
| const url = useGetDocumentUrl(); | |||
| const state = useGetChunkHighlights(selectedChunkId); | |||
| const { highlights: state, setWidthAndHeight } = | |||
| useGetChunkHighlights(selectedChunkId); | |||
| const ref = useRef<(highlight: IHighlight) => void>(() => {}); | |||
| const resetHash = () => {}; | |||
| @@ -48,58 +49,67 @@ const Preview = ({ selectedChunkId }: IProps) => { | |||
| beforeLoad={<Skeleton active />} | |||
| workerSrc="/pdfjs-dist/pdf.worker.min.js" | |||
| > | |||
| {(pdfDocument) => ( | |||
| <PdfHighlighter | |||
| pdfDocument={pdfDocument} | |||
| enableAreaSelection={(event) => event.altKey} | |||
| onScrollChange={resetHash} | |||
| scrollRef={(scrollTo) => { | |||
| ref.current = scrollTo; | |||
| }} | |||
| onSelectionFinished={() => null} | |||
| highlightTransform={( | |||
| highlight, | |||
| index, | |||
| setTip, | |||
| hideTip, | |||
| viewportToScaled, | |||
| screenshot, | |||
| isScrolledTo, | |||
| ) => { | |||
| const isTextHighlight = !Boolean( | |||
| highlight.content && highlight.content.image, | |||
| ); | |||
| {(pdfDocument) => { | |||
| pdfDocument.getPage(1).then((page) => { | |||
| const viewport = page.getViewport({ scale: 1 }); | |||
| const width = viewport.width; | |||
| const height = viewport.height; | |||
| setWidthAndHeight(width, height); | |||
| }); | |||
| const component = isTextHighlight ? ( | |||
| <Highlight | |||
| isScrolledTo={isScrolledTo} | |||
| position={highlight.position} | |||
| comment={highlight.comment} | |||
| /> | |||
| ) : ( | |||
| <AreaHighlight | |||
| isScrolledTo={isScrolledTo} | |||
| highlight={highlight} | |||
| onChange={() => {}} | |||
| /> | |||
| ); | |||
| return ( | |||
| <PdfHighlighter | |||
| pdfDocument={pdfDocument} | |||
| enableAreaSelection={(event) => event.altKey} | |||
| onScrollChange={resetHash} | |||
| scrollRef={(scrollTo) => { | |||
| ref.current = scrollTo; | |||
| }} | |||
| onSelectionFinished={() => null} | |||
| highlightTransform={( | |||
| highlight, | |||
| index, | |||
| setTip, | |||
| hideTip, | |||
| viewportToScaled, | |||
| screenshot, | |||
| isScrolledTo, | |||
| ) => { | |||
| const isTextHighlight = !Boolean( | |||
| highlight.content && highlight.content.image, | |||
| ); | |||
| return ( | |||
| <Popup | |||
| popupContent={<HighlightPopup {...highlight} />} | |||
| onMouseOver={(popupContent) => | |||
| setTip(highlight, () => popupContent) | |||
| } | |||
| onMouseOut={hideTip} | |||
| key={index} | |||
| > | |||
| {component} | |||
| </Popup> | |||
| ); | |||
| }} | |||
| highlights={state} | |||
| /> | |||
| )} | |||
| const component = isTextHighlight ? ( | |||
| <Highlight | |||
| isScrolledTo={isScrolledTo} | |||
| position={highlight.position} | |||
| comment={highlight.comment} | |||
| /> | |||
| ) : ( | |||
| <AreaHighlight | |||
| isScrolledTo={isScrolledTo} | |||
| highlight={highlight} | |||
| onChange={() => {}} | |||
| /> | |||
| ); | |||
| return ( | |||
| <Popup | |||
| popupContent={<HighlightPopup {...highlight} />} | |||
| onMouseOver={(popupContent) => | |||
| setTip(highlight, () => popupContent) | |||
| } | |||
| onMouseOut={hideTip} | |||
| key={index} | |||
| > | |||
| {component} | |||
| </Popup> | |||
| ); | |||
| }} | |||
| highlights={state} | |||
| /> | |||
| ); | |||
| }} | |||
| </PdfLoader> | |||
| </div> | |||
| ); | |||
| @@ -36,16 +36,24 @@ export const useGetSelectedChunk = (selectedChunkId: string) => { | |||
| ); | |||
| }; | |||
| export const useGetChunkHighlights = ( | |||
| selectedChunkId: string, | |||
| ): IHighlight[] => { | |||
| export const useGetChunkHighlights = (selectedChunkId: string) => { | |||
| const [size, setSize] = useState({ width: 849, height: 1200 }); | |||
| const selectedChunk: IChunk = useGetSelectedChunk(selectedChunkId); | |||
| const highlights: IHighlight[] = useMemo(() => { | |||
| return buildChunkHighlights(selectedChunk); | |||
| }, [selectedChunk]); | |||
| return buildChunkHighlights(selectedChunk, size); | |||
| }, [selectedChunk, size]); | |||
| return highlights; | |||
| const setWidthAndHeight = (width: number, height: number) => { | |||
| setSize((pre) => { | |||
| if (pre.height !== height || pre.width !== width) { | |||
| return { height, width }; | |||
| } | |||
| return pre; | |||
| }); | |||
| }; | |||
| return { highlights, setWidthAndHeight }; | |||
| }; | |||
| export const useSelectChunkListLoading = () => { | |||
| @@ -2,20 +2,20 @@ import { IChunk } from '@/interfaces/database/knowledge'; | |||
| import { UploadFile } from 'antd'; | |||
| import { v4 as uuid } from 'uuid'; | |||
| export const buildChunkHighlights = (selectedChunk: IChunk) => { | |||
| export const buildChunkHighlights = ( | |||
| selectedChunk: IChunk, | |||
| size: { width: number; height: number }, | |||
| ) => { | |||
| return Array.isArray(selectedChunk?.positions) && | |||
| selectedChunk.positions.every((x) => Array.isArray(x)) | |||
| ? selectedChunk?.positions?.map((x) => { | |||
| const actualPositions = x.map((y, index) => | |||
| index !== 0 ? y / 0.7 : y, | |||
| ); | |||
| const boundingRect = { | |||
| width: 849, | |||
| height: 1200, | |||
| x1: actualPositions[1], | |||
| x2: actualPositions[2], | |||
| y1: actualPositions[3], | |||
| y2: actualPositions[4], | |||
| width: size.width, | |||
| height: size.height, | |||
| x1: x[1], | |||
| x2: x[2], | |||
| y1: x[3], | |||
| y2: x[4], | |||
| }; | |||
| return { | |||
| id: uuid(), | |||