How to dynamically get the offset number for the carousel dots basing it off of how many slides are in view

17 Views Asked by At

We wrote a custom gallery slider/carousel for our app. We'd like to show the number of dots based on how many tiles are in view. Is this possible? Below is the code. The updated and mounted methods are Phoenix Liveview hooks. We'd like to prevent updating the code when they change their minds about the sizes of the images on mobile.

const GallerySlider: LiveHook = {
  mounted() {
    const carousel = this.el?.querySelector<HTMLElement>(".carousel")!;
    const firstImg = carousel.querySelector("div")!;
    const arrowIcons = this.el?.querySelectorAll<HTMLElement>(".wrapper i")!;
    const dots = this.el?.querySelector<HTMLElement>(".dots");
    const slideCount: number = carousel.children.length;

    let isDragStart = false;
    let isDragging = false;
    let prevPageX: number;
    let prevScrollLeft: number;
    let positionDiff: number;
    // calculate dots
    let scrollCount: number = 0;
    let isMobile = window.innerWidth >= 0 && window.innerWidth <= 768;
    let paginationOffset: number = isMobile ? 1 : 2;
    let pagination: number = slideCount - paginationOffset;

    if ((!isMobile && slideCount <= 4) || isMobile) {
      arrowIcons[0].style.display = "none";
      arrowIcons[1].style.display = "none";
    } else {
      arrowIcons[0].style.display = "block";
      arrowIcons[1].style.display = "block";
    }

    arrowIcons?.forEach((icon) =>
      icon.addEventListener("click", (e) => {
        e.preventDefault();

        const isLeft = icon.id.includes("left");
        const firstImgWidth = firstImg.clientWidth + 8;
        let scrollEnd = scrollCount + paginationOffset >= slideCount;

        carousel.scrollLeft += isLeft ? -firstImgWidth : firstImgWidth;

        // add/remove active states from dots
        if (!isLeft && !scrollEnd) {
          scrollCount += 1;

          dots?.children[scrollCount - 1].classList.remove("active");
          dots?.children[scrollCount].classList.add("active");
        }

        if (isLeft && scrollCount > 0) {
          scrollCount -= 1;

          dots?.children[scrollCount + 1].classList.remove("active");
          dots?.children[scrollCount].classList.add("active");
        }
      }),
    );

    const autoSlide = () => {
      const position =
        carousel.scrollLeft - (carousel.scrollWidth - carousel.clientWidth) >
        -1;

      if (position || carousel.scrollLeft <= 0) return;

      positionDiff = Math.abs(positionDiff);
      const firstImgWidth = firstImg.clientWidth + 16;
      const valDifference = firstImgWidth - positionDiff;

      const positionValue =
        positionDiff > firstImgWidth / 4 ? valDifference : -positionDiff;
      carousel.scrollLeft +=
        carousel.scrollLeft > prevScrollLeft ? positionValue : -positionValue;
    };

    //Dragger
    const dragStart = (e: MouseEvent | TouchEvent) => {
      isDragStart = true;
      prevPageX = "pageX" in e ? e.pageX : e.touches[0].pageX;
      prevScrollLeft = carousel.scrollLeft;
    };

    const dragging = (e: MouseEvent | TouchEvent): void => {
      if (!isDragStart) return;

      isDragging = true;

      positionDiff =
        "pageX" in e
          ? (e.pageX as number) - prevPageX
          : e.touches[0].pageX - prevPageX;

      carousel.classList.add("dragging");
      carousel.scrollLeft = prevScrollLeft - positionDiff;
    };

    const dragStop = (): void => {
      isDragStart = false;
      carousel.classList.remove("dragging");

      if (!isDragging) return;

      // add/remove active states from dots
      // positionDiff is negative as we scroll right
      let isLeft = Math.sign(positionDiff) > 0;
      let scrollEnd = scrollCount + paginationOffset >= slideCount;

      if (!isLeft && !scrollEnd) {
        scrollCount += 1;

        dots?.children[scrollCount - 1].classList.remove("active");
        dots?.children[scrollCount].classList.add("active");
      }

      if (isLeft && scrollCount > 0) {
        scrollCount -= 1;

        dots?.children[scrollCount + 1].classList.remove("active");
        dots?.children[scrollCount].classList.add("active");
      }

      isDragging = false;
      autoSlide();
    };

    /*********/
    /**dots**/
    for (let i = 0; i <= pagination && pagination > 0; i++) {
      const dot = dots?.appendChild(document.createElement("li"))!;
      if (i == 0) dot.classList.add("active");

      dot.classList.add("list-inline-item");
      dot.classList.add(i.toString());
      dot.innerHTML = i.toString();
    }
    /*********/

    carousel.addEventListener("mousedown", dragStart);
    carousel.addEventListener("touchstart", dragStart);

    document.addEventListener("mousemove", dragging);
    carousel.addEventListener("touchmove", dragging);

    document.addEventListener("mouseup", dragStop);
    carousel.addEventListener("touchend", dragStop);
  },
  updated() {
    const carousel = this.el?.querySelector<HTMLElement>(".carousel")!;
    const firstImg = carousel.querySelector("div")!;
    const arrowIcons = this.el?.querySelectorAll<HTMLElement>(".wrapper i")!;
    const dots = this.el?.querySelector<HTMLElement>(".dots");
    const slideCount: number = carousel.children.length;

    let isDragStart = false;
    let isDragging = false;
    let prevPageX: number;
    let prevScrollLeft: number;
    let positionDiff: number;
    // calculate dots
    let scrollCount: number = 0;
    let isMobile = window.innerWidth >= 0 && window.innerWidth <= 768;
    let paginationOffset: number = isMobile ? 1 : 2;
    let pagination: number = slideCount - paginationOffset;

    if ((!isMobile && slideCount <= 4) || isMobile) {
      arrowIcons[0].style.display = "none";
      arrowIcons[1].style.display = "none";
    } else {
      arrowIcons[0].style.display = "block";
      arrowIcons[1].style.display = "block";
    }

    arrowIcons?.forEach((icon) =>
      icon.addEventListener("click", (e) => {
        e.preventDefault();

        const isLeft = icon.id.includes("left");
        const firstImgWidth = firstImg.clientWidth + 8;
        let scrollEnd = scrollCount + paginationOffset >= slideCount;

        carousel.scrollLeft += isLeft ? -firstImgWidth : firstImgWidth;

        // add/remove active states from dots
        if (!isLeft && !scrollEnd) {
          scrollCount += 1;

          dots?.children[scrollCount - 1].classList.remove("active");
          dots?.children[scrollCount].classList.add("active");
        }

        if (isLeft && scrollCount > 0) {
          scrollCount -= 1;

          dots?.children[scrollCount + 1].classList.remove("active");
          dots?.children[scrollCount].classList.add("active");
        }
      }),
    );

    const autoSlide = () => {
      const position =
        carousel.scrollLeft - (carousel.scrollWidth - carousel.clientWidth) >
        -1;

      if (position || carousel.scrollLeft <= 0) return;

      positionDiff = Math.abs(positionDiff);
      const firstImgWidth = firstImg.clientWidth + 16;
      const valDifference = firstImgWidth - positionDiff;

      const positionValue =
        positionDiff > firstImgWidth / 4 ? valDifference : -positionDiff;
      carousel.scrollLeft +=
        carousel.scrollLeft > prevScrollLeft ? positionValue : -positionValue;
    };

    //Dragger
    const dragStart = (e: MouseEvent | TouchEvent) => {
      console.log("aaaa");
      isDragStart = true;
      prevPageX = "pageX" in e ? e.pageX : e.touches[0].pageX;
      prevScrollLeft = carousel.scrollLeft;
    };

    const dragging = (e: MouseEvent | TouchEvent): void => {
      if (!isDragStart) return;

      isDragging = true;

      positionDiff =
        "pageX" in e
          ? (e.pageX as number) - prevPageX
          : e.touches[0].pageX - prevPageX;

      carousel.classList.add("dragging");

      carousel.scrollLeft = prevScrollLeft - positionDiff;
    };

    const dragStop = (): void => {
      isDragStart = false;
      carousel.classList.remove("dragging");

      if (!isDragging) return;

      // add/remove active states from dots
      // positionDiff is negative as we scroll right
      let isLeft = Math.sign(positionDiff) > 0;
      let scrollEnd = scrollCount + paginationOffset >= slideCount;

      if (!isLeft && !scrollEnd) {
        scrollCount += 1;

        dots?.children[scrollCount - 1].classList.remove("active");
        dots?.children[scrollCount].classList.add("active");
      }

      if (isLeft && scrollCount > 0) {
        scrollCount -= 1;

        dots?.children[scrollCount + 1].classList.remove("active");
        dots?.children[scrollCount].classList.add("active");
      }

      isDragging = false;
      autoSlide();
    };

    /*********/
    /**dots**/
    for (let i = 0; i <= pagination && pagination > 0; i++) {
      const dot = dots?.appendChild(document.createElement("li"))!;
      if (i == 0) dot.classList.add("active");

      dot.classList.add("list-inline-item");
      dot.classList.add(i.toString());
      dot.innerHTML = i.toString();
    }
    /*********/

    carousel.addEventListener("mousedown", dragStart);
    carousel.addEventListener("touchstart", dragStart);

    document.addEventListener("mousemove", dragging);
    carousel.addEventListener("touchmove", dragging);

    document.addEventListener("mouseup", dragStop);
    carousel.addEventListener("touchend", dragStop);
  },
};

export default GallerySlider;
0

There are 0 best solutions below