I have the following code, and it is working about 90% how I want it to, it scrolls right to left, and I added a check to see when the image has reached the center of the page it should scale the image up just a little bit for effect.
This works fine for the first 3 images, but when the loop completes index 0 and index 1 never scale.
I have tried to figure this out for a while and can’t seem to determine why.
Here is a code sandbox to see it in action and to play with it
https://codesandbox.io/p/sandbox/zen-tharp-zvdwyk
Any help would be greatly appreciated
import React, { useEffect, useRef, useState } from "react";
import Marquee from "react-fast-marquee";
import styled from "styled-components";
const props = {
Carousel: [
{ image: "/1.webp" },
{ image: "/2.webp" },
{ image: "/3.webp" },
{ image: "/4.webp" },
{ image: "/5.webp" },
],
};
function Gallery() {
const [updateLoop, setUpdateLoop] = useState(false);
const [centerImageIndex, setCenterImageIndex] = useState(null);
const imgRef = useRef();
const [imageWidth, setImageWidth] = useState(0);
function isImageHorizontallyCentered(pageWidth, imageWidth, imageX) {
// Calculate the expected X coordinate for the image to be centered
const expectedX = (pageWidth - imageWidth) / 2;
// Define a margin of error, if necessary (e.g., for rounding)
const marginOfError = 10; // Adjust this value based on your requirements
// Check if the actual X coordinate is within the expected range
return Math.abs(imageX - expectedX) <= marginOfError;
}
const checkImagePosition = () => {
const pageWidth = window.innerWidth;
props.Carousel.forEach((item, index) => {
const img = document.getElementById(`image-${index}`);
const imageWidth = img.getBoundingClientRect().width;
const rect = img.getBoundingClientRect();
const imageX = rect.left + window.scrollX;
const test = isImageHorizontallyCentered(pageWidth, imageWidth, imageX);
console.log("test", test, "index", index);
if (test) {
setCenterImageIndex(index);
}
});
};
useEffect(() => {
const intervalId = setInterval(checkImagePosition, 100); // Check every 100ms
return () => clearInterval(intervalId);
}, []);
return (
<Container>
<ImagesContainer>
<Marquee speed={100} pauseOnHover>
{props?.Carousel.map((listItem, index) => {
const isCenter = index === centerImageIndex;
return (
<ImageWrapper key={index} id={`image-${index}`} center={isCenter}>
<LazyImg ref={imgRef} loading="lazy" src={listItem.image} />
</ImageWrapper>
);
})}
</Marquee>
</ImagesContainer>
</Container>
);
}
const Container = styled.div`
// width: 1200px;
// margin: 0 auto;
width: 100%;
`;
const Caption = styled.div`
color: var(--Terrace-Gray-900, #282c25);
letter-spacing: -0.32px;
align-self: center;
margin-top: 430px;
white-space: nowrap;
@media (max-width: 991px) {
white-space: initial;
}
`;
const SocialMediaText = styled.div`
align-self: center;
color: var(--Terrace-Neutral-Black, #000);
text-align: center;
letter-spacing: -2.24px;
margin-top: 8px;
font: 700 56px/114% Satoshi, sans-serif;
@media (max-width: 991px) {
max-width: 100%;
font-size: 40px;
}
`;
const ImagesContainer = styled.div`
// border: 1px solid blue;
`;
const ImageWrapper = styled.div`
// width: ${(props) => (props.center ? "800px" : "100px")};
// width: 600px;
transform: scale(${(props) => (props.center ? "1.1" : "1")});
// border: 1px solid red;
transition: transform 1s;
`;
const LazyImg = styled.img`
width: 300px;
border-radius: 50px;
background: #e0e0e0;
box-shadow: 20px 20px 60px #bebebe, -20px -20px 60px #ffffff;
//write a drop shadow
margin: 40px 40px;
`;
export default Gallery;
2
Answers
To fix the problem with the first two pics not gettin’ bigger in your picture scroll, try usin’ the
useEffect
thing to manage the state after the loop finishes. This way, the state changes only happen after the picture show is done. Also, do this "debounce" thing on thecheckImagePosition
function to slow down the calls. This can help to stop the quick and unnecessary function calls, making everything smoother and avoiding issues. These changes should help make sure the state changes sync up better with the show, making the first two pics scale up like the rest.The issue is because the way
react-fast-marquee
is implemented.Imagine the original image row being
|1-2-3|-4-5
, and first three images are in view. Now this is how it works:c1-c2-c3-c4-c5
.|1-2-3|-4-5-c1-c2-c3-c4-c5
1-2-3-|4-5-c1|-c2-c3-c4-c5
1-2-3-4-5-|c1-c2-c3|-c4-c5
->|1-2-3|-4-5-c1-c2-c3-c4-c5
This is why the first few items(1-2) never reach center of the view, and only their duplicates(c1-c2) in the copy row reach the center position.
Solution would be to consider duplicate row items as well:
Here is the working demo: https://codesandbox.io/p/sandbox/zen-onks-tktlkg?file=%2Fsrc%2FApp.js%3A42%2C1-55%2C6
Note the first image has been marked with red background.