mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-04 16:58:05 +02:00
fix: if user not provide default value use it from template in createdocument from template API
111 lines
3.9 KiB
JavaScript
111 lines
3.9 KiB
JavaScript
import { useEffect, useRef } from "react";
|
|
|
|
export default function usePdfPinchZoom(ref, scale, setScale, setZoomPercent) {
|
|
const initialDistanceRef = useRef(null);
|
|
const startScaleRef = useRef(scale);
|
|
const currentScaleRef = useRef(scale);
|
|
const pinchScaleRef = useRef(null); // stores relative scale during a gesture
|
|
const frameRef = useRef(null);
|
|
|
|
// keep a reference to the latest scale value
|
|
useEffect(() => {
|
|
const element = ref.current;
|
|
currentScaleRef.current = scale;
|
|
// once React commits the new scale after a pinch we clear the transform
|
|
if (element && !pinchScaleRef.current) {
|
|
element.style.transform = "";
|
|
}
|
|
}, [scale, ref]);
|
|
|
|
useEffect(() => {
|
|
const element = ref.current;
|
|
if (!element) return;
|
|
|
|
const getDistance = (touches) => {
|
|
const [touch1, touch2] = touches;
|
|
const dx = touch1.clientX - touch2.clientX;
|
|
const dy = touch1.clientY - touch2.clientY;
|
|
return Math.hypot(dx, dy);
|
|
};
|
|
|
|
const handleTouchStart = (e) => {
|
|
if (e.touches.length === 2) {
|
|
initialDistanceRef.current = getDistance(e.touches);
|
|
startScaleRef.current = currentScaleRef.current;
|
|
element.style.transformOrigin = "0 0";
|
|
}
|
|
};
|
|
|
|
const handleTouchMove = (e) => {
|
|
if (e.touches.length === 2 && initialDistanceRef.current) {
|
|
e.preventDefault();
|
|
const newDistance = getDistance(e.touches);
|
|
const pinchScale = newDistance / initialDistanceRef.current;
|
|
const newScale = Math.max(1, startScaleRef.current * pinchScale);
|
|
// store relative scale so it can be applied on top of current width
|
|
pinchScaleRef.current = newScale / startScaleRef.current;
|
|
|
|
if (!frameRef.current) {
|
|
frameRef.current = requestAnimationFrame(() => {
|
|
element.style.transform = `scale(${pinchScaleRef.current})`;
|
|
frameRef.current = null;
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
const handleTouchEnd = () => {
|
|
if (pinchScaleRef.current) {
|
|
let relativeScale = pinchScaleRef.current;
|
|
const inlineTransform = element.style.transform;
|
|
if (inlineTransform && inlineTransform.startsWith("scale(")) {
|
|
const value = parseFloat(inlineTransform.slice(6, -1));
|
|
if (!isNaN(value)) {
|
|
relativeScale = value;
|
|
}
|
|
}
|
|
const finalScale = Math.max(1, startScaleRef.current * relativeScale);
|
|
const percent = parseFloat(((finalScale - 1) * 100).toFixed(2));
|
|
const unchanged =
|
|
Math.abs(finalScale - currentScaleRef.current) < 0.001;
|
|
|
|
pinchScaleRef.current = null;
|
|
if (frameRef.current) {
|
|
cancelAnimationFrame(frameRef.current);
|
|
frameRef.current = null;
|
|
}
|
|
|
|
if (unchanged) {
|
|
// if scale didn't actually change, reset transform right away
|
|
element.style.transform = "";
|
|
} else {
|
|
// keep transform applied until state update reflects the new scale
|
|
element.style.transform = `scale(${relativeScale})`;
|
|
}
|
|
|
|
setScale(finalScale);
|
|
setZoomPercent(percent);
|
|
|
|
// ensure refs reflect the latest value before next gesture starts
|
|
currentScaleRef.current = finalScale;
|
|
startScaleRef.current = finalScale;
|
|
}
|
|
initialDistanceRef.current = null;
|
|
};
|
|
|
|
element.addEventListener("touchstart", handleTouchStart, {
|
|
passive: false
|
|
});
|
|
element.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
element.addEventListener("touchend", handleTouchEnd);
|
|
element.addEventListener("touchcancel", handleTouchEnd);
|
|
|
|
return () => {
|
|
element.removeEventListener("touchstart", handleTouchStart);
|
|
element.removeEventListener("touchmove", handleTouchMove);
|
|
element.removeEventListener("touchend", handleTouchEnd);
|
|
element.removeEventListener("touchcancel", handleTouchEnd);
|
|
};
|
|
}, [ref, setScale, setZoomPercent]);
|
|
}
|