NEWONE1
/
invokeai
/frontend
/web
/src
/features
/gallery
/components
/ImageViewer
/ImageComparisonHover.tsx
import { Box, Flex, Image } from '@invoke-ai/ui-library'; | |
import { useAppSelector } from 'app/store/storeHooks'; | |
import { useBoolean } from 'common/hooks/useBoolean'; | |
import { preventDefault } from 'common/util/stopPropagation'; | |
import { TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL } from 'features/controlLayers/konva/patterns/transparency-checkerboard-pattern'; | |
import type { Dimensions } from 'features/controlLayers/store/types'; | |
import { ImageComparisonLabel } from 'features/gallery/components/ImageViewer/ImageComparisonLabel'; | |
import { selectComparisonFit } from 'features/gallery/store/gallerySelectors'; | |
import { memo, useMemo, useRef } from 'react'; | |
import type { ComparisonProps } from './common'; | |
import { fitDimsToContainer, getSecondImageDims } from './common'; | |
export const ImageComparisonHover = memo(({ firstImage, secondImage, containerDims }: ComparisonProps) => { | |
const comparisonFit = useAppSelector(selectComparisonFit); | |
const imageContainerRef = useRef<HTMLDivElement>(null); | |
const mouseOver = useBoolean(false); | |
const fittedDims = useMemo<Dimensions>( | |
() => fitDimsToContainer(containerDims, firstImage), | |
[containerDims, firstImage] | |
); | |
const compareImageDims = useMemo<Dimensions>( | |
() => getSecondImageDims(comparisonFit, fittedDims, firstImage, secondImage), | |
[comparisonFit, fittedDims, firstImage, secondImage] | |
); | |
return ( | |
<Flex w="full" h="full" maxW="full" maxH="full" position="relative" alignItems="center" justifyContent="center"> | |
<Flex | |
id="image-comparison-wrapper" | |
w="full" | |
h="full" | |
maxW="full" | |
maxH="full" | |
position="absolute" | |
alignItems="center" | |
justifyContent="center" | |
> | |
<Box | |
ref={imageContainerRef} | |
position="relative" | |
id="image-comparison-hover-image-container" | |
w={fittedDims.width} | |
h={fittedDims.height} | |
maxW="full" | |
maxH="full" | |
userSelect="none" | |
overflow="hidden" | |
borderRadius="base" | |
> | |
<Image | |
id="image-comparison-hover-first-image" | |
src={firstImage.image_url} | |
fallbackSrc={firstImage.thumbnail_url} | |
w={fittedDims.width} | |
h={fittedDims.height} | |
maxW="full" | |
maxH="full" | |
objectFit="cover" | |
objectPosition="top left" | |
/> | |
<ImageComparisonLabel type="first" opacity={mouseOver.isTrue ? 0 : 1} /> | |
<Box | |
id="image-comparison-hover-second-image-container" | |
position="absolute" | |
top={0} | |
left={0} | |
right={0} | |
bottom={0} | |
overflow="hidden" | |
opacity={mouseOver.isTrue ? 1 : 0} | |
transitionDuration="0.2s" | |
transitionProperty="common" | |
> | |
<Box | |
id="image-comparison-hover-bg" | |
position="absolute" | |
top={0} | |
left={0} | |
right={0} | |
bottom={0} | |
backgroundImage={TRANSPARENCY_CHECKERBOARD_PATTERN_DARK_DATAURL} | |
backgroundRepeat="repeat" | |
/> | |
<Image | |
position="relative" | |
id="image-comparison-hover-second-image" | |
src={secondImage.image_url} | |
fallbackSrc={secondImage.thumbnail_url} | |
w={compareImageDims.width} | |
h={compareImageDims.height} | |
maxW={fittedDims.width} | |
maxH={fittedDims.height} | |
objectFit={comparisonFit} | |
objectPosition="top left" | |
/> | |
<ImageComparisonLabel type="second" opacity={mouseOver.isTrue ? 1 : 0} /> | |
</Box> | |
<Box | |
id="image-comparison-hover-interaction-overlay" | |
position="absolute" | |
top={0} | |
right={0} | |
bottom={0} | |
left={0} | |
onMouseOver={mouseOver.setTrue} | |
onMouseOut={mouseOver.setFalse} | |
onContextMenu={preventDefault} | |
userSelect="none" | |
/> | |
</Box> | |
</Flex> | |
</Flex> | |
); | |
}); | |
ImageComparisonHover.displayName = 'ImageComparisonHover'; | |