react-slick icon indicating copy to clipboard operation
react-slick copied to clipboard

CenterMode with Infinite and Variable Width not centering properly

Open joshuatuscan opened this issue 1 year ago • 5 comments

The slider is sitting in a container that is 100% the width of the viewport and width is determined by each image element child which is ultimately governed by the height of the parent container. These are native images in an img tag so they proportionally scale their aspect ratio according to the height.

The centering is off from the center by a small amount that is variable on each item. I'm not sure what is wrong with the centering calculation, but it is wrong and producing off-center results. See several screenshots below.

Screenshot 2024-02-16 at 3 47 27 PM Screenshot 2024-03-06 at 8 47 55 PM Screenshot 2024-03-06 at 8 48 29 PM

PixelSnap 2024-03-06 at 20 55 58@2x

``

 const slide_settings = {
    infinite: true,
    slidesToScroll: 1,
    slidesToShow: 1,
    arrows: false,
    dots: false,
    speed: 400,
    swipe: true,
    swipeToSlide: true,
    easing: "ease-out",
    className: "projectslider",
    variableWidth: true,
    centerMode: true,
    centerPadding: "0px",
    afterChange: (index) => {
      setCurrentMedia(index);
    },
  };
.projectslider {
  height: 100%;
  padding: 0;

  .slick-list {
    height: 100%;

    .slick-track {
      height: 100%;

      .slick-slide {
        height: 100%;

        > div {
          height: 100%;
          width: auto;

          figure {
            outline: none;
            height: 100%;
            width: auto !important;
            margin: 0;
            padding: 0 25px;
            position: relative;
            z-index: 1;

            img,
            video {
              cursor: pointer;
              height: 100%;
              outline: none;
              width: auto;
            }
          }
       }
     }
   } 
  }
}
<div className={styles.inner}>
        <Slider className={"projectslider"} ref={sliderRef} {...slide_settings}>
          {mediaData.map((media, index) =>
            media.type === "videotype" ? (
              <figure onClick={() => goToSlide(index)} key={index}>
                <video autoPlay loop playsInline muted>
                  <source src={media.videoFile} type="video/mp4" />
                </video>
              </figure>
            ) : (
              <figure key={index} onClick={() => goToSlide(index)}>
                <img
                  src={media.largeImgURL + "?auto=format"}
                  alt={media.caption}
                />
              </figure>
            )
          )}
        </Slider>
      </div>

You can see a live version here.

joshuatuscan avatar Feb 16 '24 20:02 joshuatuscan

This is 2024 and I don't want anyone to wrap their head around this issue.

The trick is using afterChange.

    const settings = {
        className: "center slider variable-width slick-gradient",
        centerMode: true,
        infinite: true,
        slidesToShow: 1,
        speed: 100,
        rows: 1,
        slidesPerRow: 1,
        arrows: false,
        centerPadding: "100px",
        beforeChange: (_oldIndex, newIndex) => {
            // ...
        },
        afterChange: (currentIndex) => {
            // Select the element with the class 'slick-track'
            var element = document.querySelector('.slick-track');

            // Get the current transform value
            var currentTransform = getComputedStyle(element).transform;

            // Extract the x translation value. The match function attempts to find the numbers in the matrix transform, which are separated by commas.
            // The matrix format is matrix(a, b, c, d, tx, ty) where tx is our x translation.
            // If the transform is in the translate3d format, it should still match correctly.
            var match = currentTransform.match(/matrix\(([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)/);

            if (match) {
                var currentX = parseFloat(match[5]); // Get the x translation value
                
                // Calculate the new x value by adding 45
                var newX = currentX + 45;
                
                // Set the new transform value
                element.style.transform = 'translate3d(' + newX + 'px, 0px, 0px)';
            } else {
                console.log("Could not parse the current transform value.");
            }
        },
        variableWidth: true,
    };

Consider to follow me if this solves your issue. :D

fzn0x avatar Apr 09 '24 11:04 fzn0x

I've been noticed that the transform was substracted by 45

so I added it back again after any slides and it solves the issue.

fzn0x avatar Apr 09 '24 11:04 fzn0x

This is 2024 and I don't want anyone to wrap their head around this issue.

The trick is using afterChange.

    const settings = {
        className: "center slider variable-width slick-gradient",
        centerMode: true,
        infinite: true,
        slidesToShow: 1,
        speed: 100,
        rows: 1,
        slidesPerRow: 1,
        arrows: false,
        centerPadding: "100px",
        beforeChange: (_oldIndex, newIndex) => {
            // ...
        },
        afterChange: (currentIndex) => {
            // Select the element with the class 'slick-track'
            var element = document.querySelector('.slick-track');

            // Get the current transform value
            var currentTransform = getComputedStyle(element).transform;

            // Extract the x translation value. The match function attempts to find the numbers in the matrix transform, which are separated by commas.
            // The matrix format is matrix(a, b, c, d, tx, ty) where tx is our x translation.
            // If the transform is in the translate3d format, it should still match correctly.
            var match = currentTransform.match(/matrix\(([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)/);

            if (match) {
                var currentX = parseFloat(match[5]); // Get the x translation value
                
                // Calculate the new x value by adding 45
                var newX = currentX + 45;
                
                // Set the new transform value
                element.style.transform = 'translate3d(' + newX + 'px, 0px, 0px)';
            } else {
                console.log("Could not parse the current transform value.");
            }
        },
        variableWidth: true,
    };

Consider to follow me if this solves your issue. :D

This actually didn't solve the problem at all, made it worse by shifting everything further and further to the right of center as you moved through the slides. Seems to have compounding result.

joshuatuscan avatar Apr 09 '24 17:04 joshuatuscan

This is 2024 and I don't want anyone to wrap their head around this issue. The trick is using afterChange.

    const settings = {
        className: "center slider variable-width slick-gradient",
        centerMode: true,
        infinite: true,
        slidesToShow: 1,
        speed: 100,
        rows: 1,
        slidesPerRow: 1,
        arrows: false,
        centerPadding: "100px",
        beforeChange: (_oldIndex, newIndex) => {
            // ...
        },
        afterChange: (currentIndex) => {
            // Select the element with the class 'slick-track'
            var element = document.querySelector('.slick-track');

            // Get the current transform value
            var currentTransform = getComputedStyle(element).transform;

            // Extract the x translation value. The match function attempts to find the numbers in the matrix transform, which are separated by commas.
            // The matrix format is matrix(a, b, c, d, tx, ty) where tx is our x translation.
            // If the transform is in the translate3d format, it should still match correctly.
            var match = currentTransform.match(/matrix\(([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)/);

            if (match) {
                var currentX = parseFloat(match[5]); // Get the x translation value
                
                // Calculate the new x value by adding 45
                var newX = currentX + 45;
                
                // Set the new transform value
                element.style.transform = 'translate3d(' + newX + 'px, 0px, 0px)';
            } else {
                console.log("Could not parse the current transform value.");
            }
        },
        variableWidth: true,
    };

Consider to follow me if this solves your issue. :D

This actually didn't solve the problem at all, made it worse by shifting everything further and further to the right of center as you moved through the slides. Seems to have compounding result.

Adds code for mobile and go to previous slide as well, see the result

// Calculate the new x value by adding 45
var newX = currentX + (device === "mobile" ? (currentSliderIndex > currentIndex ? -25 : 25) : (currentSliderIndex > currentIndex ? -45 : 45));

fzn0x avatar Apr 10 '24 03:04 fzn0x

You need to check your own tranform TX value changes.

fzn0x avatar Apr 10 '24 03:04 fzn0x