usePinchZoom
azemmur/hooks-use-pinch-zoomFreeHook
A hook to handle pinch-to-zoom gestures on touch devices.
Install it
npx shadcn@latest add https://azemmur.raouf.codes/r/hooks-use-pinch-zoom.jsonSource
1// Copyright (c) 2026 raouf.codes - Azemmur23'use client';4import { useEffect, useRef } from 'react';56export type UsePinchZoomOptions = {7 elementRef: React.RefObject<HTMLElement | null>;8 onZoom: (zoom: number) => void;9 minZoom?: number;10 maxZoom?: number;11 initialZoom?: number;12};1314function getDistance(touches: TouchList): number {15 if (touches.length < 2) return 0;16 const touch1 = touches[0];17 const touch2 = touches[1];18 if (!touch1 || !touch2) return 0;19 return Math.hypot(20 touch2.clientX - touch1.clientX,21 touch2.clientY - touch1.clientY,22 );23}2425/**26 * Hook to handle pinch-to-zoom gestures on touch devices.27 *28 * @example29 * ```tsx30 * const elementRef = useRef<HTMLDivElement>(null);31 * const [zoom, setZoom] = useState(1);32 *33 * usePinchZoom({34 * elementRef,35 * onZoom: setZoom,36 * minZoom: 0.5,37 * maxZoom: 3,38 * });39 *40 * return <div ref={elementRef} style={{ transform: `scale(${zoom})` }}>...</div>;41 * ```42 */43export function usePinchZoom({44 elementRef,45 onZoom,46 minZoom = 0.5,47 maxZoom = 3,48 initialZoom = 1,49}: UsePinchZoomOptions) {50 const currentZoom = useRef(initialZoom);51 const pinchStartDistance = useRef<number | null>(null);52 const pinchStartZoom = useRef(initialZoom);5354 useEffect(() => {55 const el = elementRef.current;56 if (!el) return;5758 const onTouchStart = (e: TouchEvent) => {59 if (e.touches.length === 2) {60 pinchStartDistance.current = getDistance(e.touches);61 pinchStartZoom.current = currentZoom.current;62 }63 };6465 const onTouchMove = (e: TouchEvent) => {66 if (e.touches.length === 2 && pinchStartDistance.current !== null) {67 e.preventDefault();6869 const currentDistance = getDistance(e.touches);70 if (currentDistance === 0) return;7172 const scale = currentDistance / pinchStartDistance.current;73 const newZoom = Math.min(74 maxZoom,75 Math.max(minZoom, pinchStartZoom.current * scale),76 );7778 currentZoom.current = newZoom;79 onZoom(newZoom);80 }81 };8283 const onTouchEnd = (e: TouchEvent) => {84 if (e.touches.length < 2) {85 pinchStartDistance.current = null;86 }87 };8889 el.addEventListener('touchstart', onTouchStart, { passive: false });90 el.addEventListener('touchmove', onTouchMove, { passive: false });91 el.addEventListener('touchend', onTouchEnd);92 el.addEventListener('touchcancel', onTouchEnd);9394 return () => {95// … truncated
Files it writes
More from Azemmur
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| useFocusTraphooks-use-focus-trap | Azemmur | Hooks | Free | no deps | |
| useIsMobilehooks-use-is-mobile | Azemmur | Hooks | Free | no deps | |
| useKeyActionshooks-use-key-actions | Azemmur | Hooks | Free | no deps | |
| useMergeRefshooks-use-merged-refs | Azemmur | Hooks | Free | no deps |
