import Panzoom from "@panzoom/panzoom"; import type { PanzoomEventDetail, PanzoomObject, } from "@panzoom/panzoom/dist/src/types"; import useTitle from "components/system/Window/useTitle"; import { useProcesses } from "contexts/process"; import useResizeObserver from "hooks/useResizeObserver"; import { basename } from "path"; import { useCallback, useEffect, useState } from "react"; export const panZoomConfig = { cursor: "default", maxScale: 7, minScale: 1, panOnlyWhenZoomed: true, step: 0.1, }; type PanZoomEvent = Event & { detail: PanzoomEventDetail }; type PanZoom = Partial< Pick > & { scale?: number }; const usePanZoom = ( id: string, imgElement: HTMLImageElement | null, containerElement: HTMLElement | null ): PanZoom => { const [panZoom, setPanZoom] = useState>(); const { getScale, reset, zoomIn, zoomOut, zoomToPoint, zoomWithWheel } = panZoom || {}; const { processes: { [id]: process }, } = useProcesses(); const { closing, componentWindow, url = "" } = process || {}; const { prependFileToTitle } = useTitle(id); const zoomUpdate = useCallback( (panZoomEvent) => { const { detail: { scale = 0, x = 0, y = 0 } = {} } = (panZoomEvent as PanZoomEvent) || {}; if (url && scale) { const { minScale, step } = panZoomConfig; const isMinScale = scale < minScale + step; if (isMinScale && (x || y)) { window.setTimeout(() => panZoom?.reset(), 50); } if (!closing) { prependFileToTitle( isMinScale ? basename(url) : `${basename(url)} (${Math.floor(scale * 100)}%)` ); } } }, [closing, panZoom, prependFileToTitle, url] ); const zoomWheel = useCallback( (event: WheelEvent) => zoomWithWheel?.(event, { step: 0.3 }), [zoomWithWheel] ); useResizeObserver(componentWindow, reset); useEffect(() => { if (imgElement && containerElement) { imgElement.addEventListener("panzoomchange", zoomUpdate); containerElement.addEventListener("wheel", zoomWheel); } return () => { imgElement?.removeEventListener("panzoomchange", zoomUpdate); containerElement?.removeEventListener("wheel", zoomWheel); }; }, [containerElement, imgElement, zoomUpdate, zoomWheel]); useEffect(() => { if (imgElement && !panZoom) { setPanZoom(Panzoom(imgElement, panZoomConfig)); } return () => panZoom?.destroy(); }, [imgElement, panZoom]); return { reset, scale: getScale?.(), zoomIn, zoomOut, zoomToPoint }; }; export default usePanZoom;