mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-04 23:36:00 -05:00
277ac91f0e
Remove `pdf-controls` feature flag and old controls GitOrigin-RevId: 807ee0aa6384df354809f4d59b10d00dadef898c
86 lines
2.9 KiB
TypeScript
86 lines
2.9 KiB
TypeScript
import { useCallback, useEffect, useRef } from 'react'
|
|
import PDFJSWrapper from '../util/pdf-js-wrapper'
|
|
|
|
// 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 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) {
|
|
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, performZoom])
|
|
}
|