Skip to content

Commit

Permalink
Adds touch support to lightbox
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-signal committed Oct 4, 2021
1 parent 4822933 commit 54e7cd2
Showing 1 changed file with 88 additions and 40 deletions.
128 changes: 88 additions & 40 deletions ts/components/Lightbox.tsx
Expand Up @@ -73,7 +73,14 @@ export function Lightbox({
const imageRef = useRef<HTMLImageElement | null>(null);
const [imagePanStyle, setImagePanStyle] = useState<CSSProperties>({});
const zoomCoordsRef = useRef<
| { screenWidth: number; screenHeight: number; x: number; y: number }
| {
initX: number;
initY: number;
screenWidth: number;
screenHeight: number;
x: number;
y: number;
}
| undefined
>();

Expand Down Expand Up @@ -231,52 +238,66 @@ export function Lightbox({
};
}, [isViewOnce, isAttachmentGIF, onTimeUpdate, playVideo, videoElement]);

const positionImage = useCallback((ev?: MouseEvent) => {
const imageNode = imageRef.current;
const zoomCoords = zoomCoordsRef.current;
if (!imageNode || !zoomCoords) {
return;
}
const positionImage = useCallback(
(ev?: { clientX: number; clientY: number }) => {
const imageNode = imageRef.current;
const zoomCoords = zoomCoordsRef.current;
if (!imageNode || !zoomCoords) {
return;
}

if (ev) {
zoomCoords.x = ev.clientX;
zoomCoords.y = ev.clientY;
}
if (ev) {
zoomCoords.x = ev.clientX;
zoomCoords.y = ev.clientY;
}

const shouldTransformX = imageNode.naturalWidth > zoomCoords.screenWidth;
const shouldTransformY = imageNode.naturalHeight > zoomCoords.screenHeight;
const shouldTransformX = imageNode.naturalWidth > zoomCoords.screenWidth;
const shouldTransformY =
imageNode.naturalHeight > zoomCoords.screenHeight;

const nextImagePanStyle: CSSProperties = {
left: '50%',
top: '50%',
};
const nextImagePanStyle: CSSProperties = {
left: '50%',
top: '50%',
};

let translateX = '-50%';
let translateY = '-50%';
let translateX = '-50%';
let translateY = '-50%';

if (shouldTransformX) {
const scaleX =
(-1 / zoomCoords.screenWidth) *
(imageNode.offsetWidth - zoomCoords.screenWidth);
if (shouldTransformX) {
const offset = imageNode.offsetWidth - zoomCoords.screenWidth;

translateX = `${zoomCoords.x * scaleX}px`;
nextImagePanStyle.left = 0;
}
const scaleX = (-1 / zoomCoords.screenWidth) * offset;

if (shouldTransformY) {
const scaleY =
(-1 / zoomCoords.screenHeight) *
(imageNode.offsetHeight - zoomCoords.screenHeight);
const posX = Math.max(
0,
Math.min(zoomCoords.screenWidth, zoomCoords.x)
);

translateY = `${zoomCoords.y * scaleY}px`;
nextImagePanStyle.top = 0;
}
translateX = `${posX * scaleX}px`;
nextImagePanStyle.left = 0;
}

setImagePanStyle({
...nextImagePanStyle,
transform: `translate(${translateX}, ${translateY})`,
});
}, []);
if (shouldTransformY) {
const offset = imageNode.offsetHeight - zoomCoords.screenHeight;

const scaleY = (-1 / zoomCoords.screenHeight) * offset;

const posY = Math.max(
0,
Math.min(zoomCoords.screenHeight, zoomCoords.y)
);

translateY = `${posY * scaleY}px`;
nextImagePanStyle.top = 0;
}

setImagePanStyle({
...nextImagePanStyle,
transform: `translate(${translateX}, ${translateY})`,
});
},
[]
);

function canPanImage(): boolean {
const imageNode = imageRef.current;
Expand All @@ -288,21 +309,46 @@ export function Lightbox({
);
}

const handleTouchMove = useCallback(
(ev: TouchEvent) => {
const imageNode = imageRef.current;
const zoomCoords = zoomCoordsRef.current;

ev.preventDefault();
ev.stopPropagation();

if (!imageNode || !zoomCoords) {
return;
}

const [touch] = ev.touches;
const { initX, initY } = zoomCoords;

positionImage({
clientX: initX + (initX - touch.clientX),
clientY: initY + (initY - touch.clientY),
});
},
[positionImage]
);

useEffect(() => {
const imageNode = imageRef.current;
let hasListener = false;

if (imageNode && zoomType !== ZoomType.None && canPanImage()) {
hasListener = true;
document.addEventListener('mousemove', positionImage);
document.addEventListener('touchmove', handleTouchMove);
}

return () => {
if (hasListener) {
document.removeEventListener('mousemove', positionImage);
document.removeEventListener('touchmove', handleTouchMove);
}
};
}, [positionImage, zoomType]);
}, [handleTouchMove, positionImage, zoomType]);

const caption = attachment?.caption;

Expand Down Expand Up @@ -346,8 +392,10 @@ export function Lightbox({
if (canPanImage()) {
setZoomType(ZoomType.ZoomAndPan);
zoomCoordsRef.current = {
screenWidth: document.documentElement.clientWidth,
initX: event.clientX,
initY: event.clientY,
screenHeight: document.documentElement.clientHeight,
screenWidth: document.documentElement.clientWidth,
x: event.clientX,
y: event.clientY,
};
Expand Down

0 comments on commit 54e7cd2

Please sign in to comment.