mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-15 05:37:32 +00:00
fix: image preview (#2786)
Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
@@ -10,7 +10,7 @@ export const useZoomControls = ({
|
|||||||
zoomRef,
|
zoomRef,
|
||||||
imageRef,
|
imageRef,
|
||||||
}: UseZoomControlsProps) => {
|
}: UseZoomControlsProps) => {
|
||||||
const [currentScale, setCurrentScale] = useState<number>(0.5);
|
const [currentScale, setCurrentScale] = useState<number>(1);
|
||||||
const [isZoomedBigger, setIsZoomedBigger] = useState<boolean>(false);
|
const [isZoomedBigger, setIsZoomedBigger] = useState<boolean>(false);
|
||||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||||
const [mouseX, setMouseX] = useState<number>(0);
|
const [mouseX, setMouseX] = useState<number>(0);
|
||||||
@@ -35,28 +35,60 @@ export const useZoomControls = ({
|
|||||||
|
|
||||||
const zoomOut = useCallback(() => {
|
const zoomOut = useCallback(() => {
|
||||||
const image = imageRef.current;
|
const image = imageRef.current;
|
||||||
if (image && currentScale > 0.5) {
|
if (image && currentScale > 0.2) {
|
||||||
const newScale = currentScale - 0.1;
|
const newScale = currentScale - 0.1;
|
||||||
setCurrentScale(newScale);
|
setCurrentScale(newScale);
|
||||||
image.style.width = `${image.naturalWidth * newScale}px`;
|
image.style.width = `${image.naturalWidth * newScale}px`;
|
||||||
image.style.height = `${image.naturalHeight * newScale}px`;
|
image.style.height = `${image.naturalHeight * newScale}px`;
|
||||||
if (!isZoomedBigger) {
|
const zoomedWidth = image.naturalWidth * newScale;
|
||||||
|
const zoomedHeight = image.naturalHeight * newScale;
|
||||||
|
const containerWidth = window.innerWidth;
|
||||||
|
const containerHeight = window.innerHeight;
|
||||||
|
if (zoomedWidth > containerWidth || zoomedHeight > containerHeight) {
|
||||||
image.style.transform = `translate(0px, 0px)`;
|
image.style.transform = `translate(0px, 0px)`;
|
||||||
|
setImagePos({ x: 0, y: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [imageRef, currentScale, isZoomedBigger]);
|
}, [imageRef, currentScale]);
|
||||||
|
|
||||||
|
const checkZoomSize = useCallback(() => {
|
||||||
|
const { current: zoomArea } = zoomRef;
|
||||||
|
if (zoomArea) {
|
||||||
|
const image = zoomArea.querySelector('img');
|
||||||
|
if (image) {
|
||||||
|
const zoomedWidth = image.naturalWidth * currentScale;
|
||||||
|
const zoomedHeight = image.naturalHeight * currentScale;
|
||||||
|
const containerWidth = window.innerWidth;
|
||||||
|
const containerHeight = window.innerHeight;
|
||||||
|
setIsZoomedBigger(
|
||||||
|
zoomedWidth > containerWidth || zoomedHeight > containerHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [currentScale, zoomRef]);
|
||||||
|
|
||||||
const resetZoom = useCallback(() => {
|
const resetZoom = useCallback(() => {
|
||||||
const image = imageRef.current;
|
const image = imageRef.current;
|
||||||
if (image) {
|
if (image) {
|
||||||
const newScale = 0.5;
|
const viewportWidth = window.innerWidth;
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
const margin = 0.2;
|
||||||
|
|
||||||
|
const availableWidth = viewportWidth * (1 - margin);
|
||||||
|
const availableHeight = viewportHeight * (1 - margin);
|
||||||
|
|
||||||
|
const widthRatio = availableWidth / image.naturalWidth;
|
||||||
|
const heightRatio = availableHeight / image.naturalHeight;
|
||||||
|
|
||||||
|
const newScale = Math.min(widthRatio, heightRatio);
|
||||||
setCurrentScale(newScale);
|
setCurrentScale(newScale);
|
||||||
image.style.width = `${image.naturalWidth * newScale}px`;
|
image.style.width = `${image.naturalWidth * newScale}px`;
|
||||||
image.style.height = `${image.naturalHeight * newScale}px`;
|
image.style.height = `${image.naturalHeight * newScale}px`;
|
||||||
image.style.transform = `translate(0px, 0px)`;
|
image.style.transform = 'translate(0px, 0px)';
|
||||||
setImagePos({ x: 0, y: 0 });
|
setImagePos({ x: 0, y: 0 });
|
||||||
|
checkZoomSize();
|
||||||
}
|
}
|
||||||
}, [imageRef]);
|
}, [checkZoomSize, imageRef]);
|
||||||
|
|
||||||
const handleDragStart = useCallback(
|
const handleDragStart = useCallback(
|
||||||
(event: ReactMouseEvent) => {
|
(event: ReactMouseEvent) => {
|
||||||
@@ -138,22 +170,6 @@ export const useZoomControls = ({
|
|||||||
}
|
}
|
||||||
}, [isDragging, dragEndImpl]);
|
}, [isDragging, dragEndImpl]);
|
||||||
|
|
||||||
const checkZoomSize = useCallback(() => {
|
|
||||||
const { current: zoomArea } = zoomRef;
|
|
||||||
if (zoomArea) {
|
|
||||||
const image = zoomArea.querySelector('img');
|
|
||||||
if (image) {
|
|
||||||
const zoomedWidth = image.naturalWidth * currentScale;
|
|
||||||
const zoomedHeight = image.naturalHeight * currentScale;
|
|
||||||
const containerWidth = window.innerWidth;
|
|
||||||
const containerHeight = window.innerHeight;
|
|
||||||
setIsZoomedBigger(
|
|
||||||
zoomedWidth > containerWidth || zoomedHeight > containerHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [currentScale, zoomRef]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = (event: WheelEvent) => {
|
const handleScroll = (event: WheelEvent) => {
|
||||||
const { deltaY } = event;
|
const { deltaY } = event;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const imagePreviewModalGoStyle = style({
|
|||||||
export const imageNavigationControlStyle = style({
|
export const imageNavigationControlStyle = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
zIndex: 0,
|
zIndex: 2,
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ const ImagePreviewModalImpl = (
|
|||||||
if (!url) {
|
if (!url) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextImageHandler = (blockId: string | null) => {
|
const nextImageHandler = (blockId: string | null) => {
|
||||||
assertExists(blockId);
|
assertExists(blockId);
|
||||||
const workspace = props.workspace;
|
const workspace = props.workspace;
|
||||||
@@ -120,12 +121,6 @@ const ImagePreviewModalImpl = (
|
|||||||
);
|
);
|
||||||
if (nextBlock) {
|
if (nextBlock) {
|
||||||
setBlockId(nextBlock.id);
|
setBlockId(nextBlock.id);
|
||||||
const image = imageRef.current;
|
|
||||||
resetZoom();
|
|
||||||
if (image) {
|
|
||||||
image.style.width = '50%'; // Reset the width to its original size
|
|
||||||
image.style.height = 'auto'; // Reset the height to maintain aspect ratio
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -143,12 +138,6 @@ const ImagePreviewModalImpl = (
|
|||||||
);
|
);
|
||||||
if (prevBlock) {
|
if (prevBlock) {
|
||||||
setBlockId(prevBlock.id);
|
setBlockId(prevBlock.id);
|
||||||
const image = imageRef.current;
|
|
||||||
if (image) {
|
|
||||||
resetZoom();
|
|
||||||
image.style.width = '50%'; // Reset the width to its original size
|
|
||||||
image.style.height = 'auto'; // Reset the height to maintain aspect ratio
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -173,12 +162,6 @@ const ImagePreviewModalImpl = (
|
|||||||
);
|
);
|
||||||
if (prevBlock) {
|
if (prevBlock) {
|
||||||
setBlockId(prevBlock.id);
|
setBlockId(prevBlock.id);
|
||||||
const image = imageRef.current;
|
|
||||||
resetZoom();
|
|
||||||
if (image) {
|
|
||||||
image.style.width = '100%'; // Reset the width to its original size
|
|
||||||
image.style.height = 'auto'; // Reset the height to maintain aspect ratio
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
page
|
page
|
||||||
@@ -278,33 +261,43 @@ const ImagePreviewModalImpl = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-testid="image-preview-modal" className={imagePreviewModalStyle}>
|
<div
|
||||||
<div className={imageNavigationControlStyle}>
|
data-testid="image-preview-modal"
|
||||||
<span
|
className={imagePreviewModalStyle}
|
||||||
className={imagePreviewModalGoStyle}
|
onClick={event =>
|
||||||
style={{
|
event.target === event.currentTarget ? props.onClose() : null
|
||||||
left: 0,
|
}
|
||||||
}}
|
>
|
||||||
onClick={() => {
|
{!isZoomedBigger ? (
|
||||||
assertExists(blockId);
|
<div className={imageNavigationControlStyle}>
|
||||||
previousImageHandler(blockId);
|
<span
|
||||||
}}
|
className={imagePreviewModalGoStyle}
|
||||||
>
|
style={{
|
||||||
❮
|
left: 0,
|
||||||
</span>
|
}}
|
||||||
<span
|
onClick={() => {
|
||||||
className={imagePreviewModalGoStyle}
|
assertExists(blockId);
|
||||||
style={{
|
previousImageHandler(blockId);
|
||||||
right: 0,
|
}}
|
||||||
}}
|
>
|
||||||
onClick={() => {
|
❮
|
||||||
assertExists(blockId);
|
</span>
|
||||||
nextImageHandler(blockId);
|
<span
|
||||||
}}
|
className={imagePreviewModalGoStyle}
|
||||||
>
|
style={{
|
||||||
❯
|
right: 0,
|
||||||
</span>
|
}}
|
||||||
</div>
|
onClick={() => {
|
||||||
|
assertExists(blockId);
|
||||||
|
nextImageHandler(blockId);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
❯
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
<div className={imagePreviewModalContainerStyle}>
|
<div className={imagePreviewModalContainerStyle}>
|
||||||
<div
|
<div
|
||||||
className={clsx('zoom-area', { 'zoomed-bigger': isZoomedBigger })}
|
className={clsx('zoom-area', { 'zoomed-bigger': isZoomedBigger })}
|
||||||
@@ -322,7 +315,7 @@ const ImagePreviewModalImpl = (
|
|||||||
onMouseUp={handleDragEnd}
|
onMouseUp={handleDragEnd}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
width={'50%'}
|
onLoad={resetZoom}
|
||||||
/>
|
/>
|
||||||
{isZoomedBigger ? null : (
|
{isZoomedBigger ? null : (
|
||||||
<p className={imagePreviewModalCaptionStyle}>{caption}</p>
|
<p className={imagePreviewModalCaptionStyle}>{caption}</p>
|
||||||
@@ -356,6 +349,7 @@ const ImagePreviewModalImpl = (
|
|||||||
className={imageBottomContainerStyle}
|
className={imageBottomContainerStyle}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
|
onClick={event => event.stopPropagation()}
|
||||||
>
|
>
|
||||||
{isZoomedBigger && caption !== '' ? (
|
{isZoomedBigger && caption !== '' ? (
|
||||||
<p className={captionStyle}>{caption}</p>
|
<p className={captionStyle}>{caption}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user