mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
refactored media components
This commit is contained in:
parent
b551fc44ea
commit
d757b74fd0
9 changed files with 6 additions and 210 deletions
109
src/components/common/PinchZoom/index.tsx
Normal file
109
src/components/common/PinchZoom/index.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
import {
|
||||
FC,
|
||||
ReactElement,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
interface Props {
|
||||
children: (props: {
|
||||
setRef: (ref: HTMLElement | null) => void;
|
||||
}) => ReactElement;
|
||||
}
|
||||
|
||||
const getDistance = (event: TouchEvent) => {
|
||||
return Math.hypot(
|
||||
event.touches[0].pageX - event.touches[1].pageX,
|
||||
event.touches[0].pageY - event.touches[1].pageY,
|
||||
);
|
||||
};
|
||||
|
||||
interface Start {
|
||||
x: number;
|
||||
y: number;
|
||||
distance: number;
|
||||
}
|
||||
|
||||
const PinchZoom: FC<Props> = ({ children }) => {
|
||||
const start = useRef<Start>({ x: 0, y: 0, distance: 0 });
|
||||
const [ref, setRef] = useState<HTMLElement | null>(null);
|
||||
const imageElementScale = useRef(1);
|
||||
|
||||
const onTouchStart = useCallback((event: TouchEvent) => {
|
||||
if (event.touches.length !== 2) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault(); // Prevent page scroll
|
||||
|
||||
// Calculate where the fingers have started on the X and Y axis
|
||||
start.current.x = (event.touches[0].pageX + event.touches[1].pageX) / 2;
|
||||
start.current.y = (event.touches[0].pageY + event.touches[1].pageY) / 2;
|
||||
start.current.distance = getDistance(event);
|
||||
}, []);
|
||||
|
||||
const onTouchMove = useCallback(
|
||||
(event) => {
|
||||
if (event.touches.length !== 2 || !ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault(); // Prevent page scroll
|
||||
|
||||
// Safari provides event.scale as two fingers move on the screen
|
||||
// For other browsers just calculate the scale manually
|
||||
const scale = event.scale ?? getDistance(event) / start.current.distance;
|
||||
imageElementScale.current = Math.min(Math.max(1, scale), 4);
|
||||
|
||||
// Calculate how much the fingers have moved on the X and Y axis
|
||||
const deltaX =
|
||||
((event.touches[0].pageX + event.touches[1].pageX) / 2 -
|
||||
start.current.x) *
|
||||
2; // x2 for accelarated movement
|
||||
const deltaY =
|
||||
((event.touches[0].pageY + event.touches[1].pageY) / 2 -
|
||||
start.current.y) *
|
||||
2; // x2 for accelarated movement
|
||||
|
||||
// Transform the image to make it grow and move with fingers
|
||||
const transform = `translate3d(${deltaX}px, ${deltaY}px, 0) scale(${imageElementScale})`;
|
||||
ref.style.transform = transform;
|
||||
ref.style.zIndex = '9999';
|
||||
},
|
||||
[ref],
|
||||
);
|
||||
|
||||
const onTouchEnd = useCallback(
|
||||
(event) => {
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset image to it's original format
|
||||
ref.style.transform = '';
|
||||
ref.style.zIndex = '';
|
||||
},
|
||||
[ref],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
ref.addEventListener('touchstart', onTouchStart);
|
||||
ref.addEventListener('touchmove', onTouchMove);
|
||||
ref.addEventListener('touchend', onTouchEnd);
|
||||
|
||||
return () => {
|
||||
ref.removeEventListener('touchstart', onTouchStart);
|
||||
ref.removeEventListener('touchmove', onTouchMove);
|
||||
ref.removeEventListener('touchend', onTouchEnd);
|
||||
};
|
||||
}, [onTouchEnd, onTouchMove, onTouchStart, ref]);
|
||||
|
||||
return children({ setRef });
|
||||
};
|
||||
|
||||
export { PinchZoom };
|
Loading…
Add table
Add a link
Reference in a new issue