mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #19239 from overleaf/dp-scroll-wheel-zoom
Implement pdf mouse wheel zooming GitOrigin-RevId: d69570bb5a54970072d6f602792ddb1159343423
This commit is contained in:
parent
3e81e212f3
commit
4fe66c0189
2 changed files with 92 additions and 0 deletions
|
@ -16,6 +16,7 @@ import { debugConsole } from '@/utils/debugging'
|
|||
import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import usePresentationMode from '../hooks/use-presentation-mode'
|
||||
import useMouseWheelZoom from '../hooks/use-mouse-wheel-zoom'
|
||||
|
||||
type PdfJsViewerProps = {
|
||||
url: string
|
||||
|
@ -467,6 +468,8 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
|
|||
[initialised, setZoom]
|
||||
)
|
||||
|
||||
useMouseWheelZoom(pdfJsWrapper, setScale)
|
||||
|
||||
const requestPresentationMode = usePresentationMode(
|
||||
pdfJsWrapper,
|
||||
page,
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import PDFJSWrapper from '../util/pdf-js-wrapper'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
// We need this to work for both a traditional mouse wheel and a touchpad "pinch to zoom".
|
||||
// From experimentation, trackpads tend to fire a lot of events with small deltaY's where
|
||||
// as a mouse wheel will fire fewer events but sometimes with a very high deltaY if you
|
||||
// move the wheel quickly.
|
||||
// The divisor is set to a value that works for the trackpad with the maximum value ensuring
|
||||
// that the scale doesn't suddenly change drastically from moving the mouse wheel quickly.
|
||||
const MAX_SCALE_FACTOR = 1.2
|
||||
const SCALE_FACTOR_DIVISOR = 20
|
||||
|
||||
export default function useMouseWheelZoom(
|
||||
pdfJsWrapper: PDFJSWrapper | null | undefined,
|
||||
setScale: (scale: string) => void
|
||||
) {
|
||||
const isEnabled = useFeatureFlag('pdf-controls')
|
||||
|
||||
const isZoomingRef = useRef(false)
|
||||
|
||||
const performZoom = useCallback(
|
||||
(event: WheelEvent, pdfJsWrapper: PDFJSWrapper) => {
|
||||
// First, we calculate and set the new scale
|
||||
const scrollMagnitude = Math.abs(event.deltaY)
|
||||
const scaleFactorMagnitude = Math.min(
|
||||
1 + scrollMagnitude / SCALE_FACTOR_DIVISOR,
|
||||
MAX_SCALE_FACTOR
|
||||
)
|
||||
const previousScale = pdfJsWrapper.viewer.currentScale
|
||||
const scaleChangeDirection = Math.sign(event.deltaY)
|
||||
|
||||
const approximateScaleFactor =
|
||||
scaleChangeDirection < 0
|
||||
? scaleFactorMagnitude
|
||||
: 1 / scaleFactorMagnitude
|
||||
|
||||
const newScale =
|
||||
Math.round(previousScale * approximateScaleFactor * 100) / 100
|
||||
const exactScaleFactor = newScale / previousScale
|
||||
|
||||
// Set the scale directly to ensure it is set before we do the scrolling below
|
||||
pdfJsWrapper.viewer.currentScale = newScale
|
||||
setScale(`${newScale}`)
|
||||
|
||||
// Then we need to ensure we are centering the zoom on the mouse position
|
||||
const containerRect = pdfJsWrapper.container.getBoundingClientRect()
|
||||
const top = containerRect.top
|
||||
const left = containerRect.left
|
||||
|
||||
// Positions relative to pdf viewer
|
||||
const currentMouseX = event.clientX - left
|
||||
const currentMouseY = event.clientY - top
|
||||
|
||||
pdfJsWrapper.container.scrollBy({
|
||||
left: currentMouseX * exactScaleFactor - currentMouseX,
|
||||
top: currentMouseY * exactScaleFactor - currentMouseY,
|
||||
behavior: 'instant',
|
||||
})
|
||||
},
|
||||
[setScale]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (pdfJsWrapper && isEnabled) {
|
||||
const wheelListener = (event: WheelEvent) => {
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
event.preventDefault()
|
||||
|
||||
if (!isZoomingRef.current) {
|
||||
isZoomingRef.current = true
|
||||
|
||||
performZoom(event, pdfJsWrapper)
|
||||
|
||||
setTimeout(() => {
|
||||
isZoomingRef.current = false
|
||||
}, 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdfJsWrapper.container.addEventListener('wheel', wheelListener)
|
||||
|
||||
return () => {
|
||||
pdfJsWrapper.container.removeEventListener('wheel', wheelListener)
|
||||
}
|
||||
}
|
||||
}, [pdfJsWrapper, setScale, isEnabled, performZoom])
|
||||
}
|
Loading…
Reference in a new issue