From 64e1192c7ecdb5893023b43ba4e82a153be18fb9 Mon Sep 17 00:00:00 2001 From: Samuel Pelletier Evraire Date: Mon, 17 Jun 2024 18:04:54 +0000 Subject: [PATCH] Adding zoom img --- src/Components/Carousel/Carousel.css | 1 + src/Components/Carousel/Carousel.tsx | 9 +- .../ImageZoomInOut/ImageZoomInOut.css | 21 +++ .../ImageZoomInOut/ImageZoomInOut.tsx | 127 ++++++++++++++++++ src/Components/Modal/Modal.tsx | 8 +- src/Pages/FormPage/FormPage.tsx | 33 ++--- 6 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 src/Components/ImageZoomInOut/ImageZoomInOut.css create mode 100644 src/Components/ImageZoomInOut/ImageZoomInOut.tsx diff --git a/src/Components/Carousel/Carousel.css b/src/Components/Carousel/Carousel.css index 2b9e149d..27aa070c 100644 --- a/src/Components/Carousel/Carousel.css +++ b/src/Components/Carousel/Carousel.css @@ -31,6 +31,7 @@ transition: all 750ms linear; width: 100%; height: fit-content; + max-height: 100px; object-fit: contain; } diff --git a/src/Components/Carousel/Carousel.tsx b/src/Components/Carousel/Carousel.tsx index 9c0273c4..161f812e 100644 --- a/src/Components/Carousel/Carousel.tsx +++ b/src/Components/Carousel/Carousel.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import "./Carousel.css"; +import ImageZoomInOut from "../ImageZoomInOut/ImageZoomInOut"; interface CarouselProps { imgs: { url: string; @@ -45,11 +46,15 @@ const Carousel: React.FC = ({ imgs }) => { selectImg(currImg - 1)}> ❮ - 0 ? imgList[currImg].url : ""} + alt="no picture"/> + {/* 0 ? imgList[currImg].url : ""} alt={imgList.length > 0 ? imgList[currImg].title : "No picture"} - > + >*/} selectImg(currImg + 1)}> ❯ diff --git a/src/Components/ImageZoomInOut/ImageZoomInOut.css b/src/Components/ImageZoomInOut/ImageZoomInOut.css new file mode 100644 index 00000000..f0616fc4 --- /dev/null +++ b/src/Components/ImageZoomInOut/ImageZoomInOut.css @@ -0,0 +1,21 @@ +.btn-container { + display: flex; + flex-direction: column; + gap: 8px; + background-color: #fff; + border-radius: 8px; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + z-index: 1; + border:1px solid black; + } + +.btn-container button { + border: none; + color: #737373; + background-color: #fff; + padding: 10px; + cursor: pointer; + } \ No newline at end of file diff --git a/src/Components/ImageZoomInOut/ImageZoomInOut.tsx b/src/Components/ImageZoomInOut/ImageZoomInOut.tsx new file mode 100644 index 00000000..e079fb34 --- /dev/null +++ b/src/Components/ImageZoomInOut/ImageZoomInOut.tsx @@ -0,0 +1,127 @@ +import { useState, useRef, useEffect } from "react"; +import "./ImageZoomInOut.css"; + +interface ImageProps { + imageUrl: string; + className?: string; // Optional class name + onClick?: () => void; // Optional click handler function +} + +function ImageZoomInOut({ imageUrl, className, onClick }: ImageProps) { + const [scale, setScale] = useState(1); + const [position, setPosition] = useState({ x: 0, y: 0 }); + const imageRef = useRef(null); + const intervalRef = useRef(null)||scale>1; + + const handleHoldZoomIn = () => { + if (intervalRef.current && (scale + 0.05 < 1)) return; + intervalRef.current = setInterval(() => { + handleZoomIn(); + }, 1); + }; + + const handleHoldZoomOut = () => { + if (intervalRef.current && (scale + 0.05 < 1)) return; + intervalRef.current = setInterval(() => { + handleZoomOut(); + }, 1); + }; + + const handleHoldZoomInOutStop = () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + intervalRef.current = null; + } + }; + + const handleZoomIn = () => { + if (scale + 0.05 > 1) { + setScale((scale) => scale + 0.05); + }else{ + setScale(1); + handleHoldZoomInOutStop(); + } + }; + + const handleZoomOut = () => { + if (scale - 0.05 > 1) { + setScale((scale) => scale - 0.05); + }else{ + setScale(1); + handleHoldZoomInOutStop(); + } + }; + + useEffect(() => { + const image = imageRef.current as unknown as HTMLImageElement; + let isDragging = false; + let prevPosition = { x: 0, y: 0 }; + + const handleMouseDown = (e: MouseEvent) => { + isDragging = true; + prevPosition = { x: e.clientX, y: e.clientY }; + }; + + const handleMouseMove = (e: MouseEvent) => { + if (!isDragging) return; + const deltaX = e.clientX - prevPosition.x; + const deltaY = e.clientY - prevPosition.y; + prevPosition = { x: e.clientX, y: e.clientY }; + setPosition((position) => ({ + x: position.x + deltaX, + y: position.y + deltaY, + })); + }; + + const handleMouseUp = () => { + isDragging = false; + }; + + image?.addEventListener("mousedown", handleMouseDown); + image?.addEventListener("mousemove", handleMouseMove); + image?.addEventListener("mouseup", handleMouseUp); + + return () => { + image?.removeEventListener("mousedown", handleMouseDown); + image?.removeEventListener("mousemove", handleMouseMove); + image?.removeEventListener("mouseup", handleMouseUp); + }; + }, [imageRef, scale]); + + return ( +
+
+ + +
+ + No Picture +
+ ); +} + +export default ImageZoomInOut; diff --git a/src/Components/Modal/Modal.tsx b/src/Components/Modal/Modal.tsx index 7ecfd6fb..1bac2f14 100644 --- a/src/Components/Modal/Modal.tsx +++ b/src/Components/Modal/Modal.tsx @@ -5,7 +5,9 @@ import Carousel from "../Carousel/Carousel"; interface ModalProps { text: string; imgs: Image[]; // Array of Image objects - handleTextChange: (event: { target: { value: React.SetStateAction }; }) => void; + handleTextChange: (event: { + target: { value: React.SetStateAction }; + }) => void; close: () => void; toRef: React.MutableRefObject; } @@ -48,8 +50,8 @@ const Modal: React.FC = ({ return (
- -
+ +
{ // @ts-expect-error : setForm is going to be used when linked to db // eslint-disable-next-line @@ -109,10 +108,6 @@ const FormPage = () => { }[] >([]); - // Load data from environment variable or local JSON file - const [useLocalData, setUseLocalData] = useState(process.env.REACT_APP_ACTIVATE_USING_JSON); - - const [data, setData] = useState( new dataObject([ new section("Company information", "company", [ @@ -215,7 +210,7 @@ const FormPage = () => { return (
@@ -223,7 +218,7 @@ const FormPage = () => { id={parent.label + "-" + inputInfo.label} ref={ textareas.find( - (obj) => obj.label === parent.label + inputInfo.label + (obj) => obj.label === parent.label + inputInfo.label, )?.ref } value={inputInfo.value} @@ -250,18 +245,23 @@ const FormPage = () => { .reduce((sum, current) => sum + current) > 3 && (
-