skip to Main Content

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


  1. 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 the checkImagePosition 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.

    Login or Signup to reply.
  2. 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:

    • It creates a copy of the items row, say c1-c2-c3-c4-c5.
    • The copy row is attached to the first one from right.
      |1-2-3|-4-5-c1-c2-c3-c4-c5
    • Then it moves both the rows towards right.
      1-2-3-|4-5-c1|-c2-c3-c4-c5
    • The moment the first row gets out of the view from left, it resets both the rows to original position.
      1-2-3-4-5-|c1-c2-c3|-c4-c5 -> |1-2-3|-4-5-c1-c2-c3-c4-c5
    • and the cycle repeats

    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:

    const checkImagePosition = () => {
        const pageWidth = window.innerWidth;
    
        outer: for (let index = 0; index < props.Carousel.length; index++) {
          // narrow the following query further to avoid conflicts with other stuff on the page
          const images = document.querySelectorAll(`[id="image-${index}"`);
    
          for (const img of images) {
            const rect = img.getBoundingClientRect();
            const imageWidth = rect.width;
            const imageX = rect.left + window.scrollX;
    
            const test = isImageHorizontallyCentered(pageWidth, imageWidth, imageX);
            if (test) {
              setCenterImageIndex(index);
              // to improve the performance break the loops after we find the center image
              break outer;
            }
          }
        }
      };
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search