Angular Carousel Scrolling Issue: Cards Not Moving on Swipe

  Kiến thức lập trình

I’m building a frontend interface for my anime API, so I used FetchApiDataService to fetch the anime list. I arranged all the anime in cards, and my idea was to implement a “carousel” due to the large number of anime. I set it up to show 5 cards at a time, with the remaining cards appearing when the user scrolls (using mouse or finger) or clicks the buttons to the left or right.

<!-- anime-card.component.html -->
<div class="container">
    <button (click)="showPrevCard()">Prev</button>
    <div class="card-carousel" 
    *ngFor="let anime of visibleAnimes; let i = index" 
    [ngClass]="{'main-card': i === 2, 'big-card': i === 1 || i === 3, 'small-card': i === 0 || i === 4}"
    (mousedown)="startDrag($event)"
    (touchstart)="startDrag($event)"
    (mousemove)="onDrag($event)"
    (touchmove)="onDrag($event)"
    (mouseup)="endDrag()"
    (touchend)="endDrag()">
        <mat-card class="poster">
            <img [src]="anime.ImagePath" [alt]="anime.Title" />
            <mat-card-header>
                <mat-card-title>{{ anime.Title }}</mat-card-title>
                <mat-card-subtitle>The Manga writers is: {{ anime.MangaArtist?.Name }}</mat-card-subtitle>
                <mat-card-content>
                    <div class="tags">
                        <span *ngFor="let genre of anime.Genre.Name; let i = index"
                            [ngStyle]="{'background-color': getGenreColor(i)}">{{ genre }}</span>
                    </div>
                    <div class="btn">
                        <a [routerLink]="['/animes', anime.Title]">Description</a>
                    </div>
                </mat-card-content>
            </mat-card-header>
        </mat-card>
    </div>
    <button (click)="showNextCard()">Next</button>
</div>
// anime-card.component.ts
import { Component, OnInit, ChangeDetectorRef, HostListener } from '@angular/core';
import { FetchApiDataService } from '../fetch-api-data.service';

@Component({
  selector: 'app-anime-card',
  templateUrl: './anime-card.component.html',
  styleUrls: ['./anime-card.component.scss']
})
export class AnimeCardComponent implements OnInit {
  allAnimes: any[] = [];
  visibleAnimes: any[] = [];
  currentIndex = 0;
  displayCount = 5;
  centerIndex = 2;

  private startX = 0;
  private currentX = 0;
  private isDragging = false;

  constructor(
    private fetchApiDataService: FetchApiDataService,
    private cd: ChangeDetectorRef
  ) { }

  ngOnInit(): void {
    this.fetchApiDataService.getAllAnimes().subscribe((animes: any) => {
      this.allAnimes = animes;
      this.updateVisibleAnimes();
    });
  }

  updateVisibleAnimes() {
    this.visibleAnimes = [];
    for (let i = 0; i < this.displayCount; i++) {
      let anime = this.allAnimes[(this.currentIndex + i) % this.allAnimes.length];
      let x = i - this.centerIndex;
      let scale = this.calcScale(x);
      let leftPos = this.calcPos(x, scale);
      anime.transform = `translateX(${leftPos}%) scale(${scale})`;
      this.visibleAnimes.push(anime);
    }
    this.cd.detectChanges();
  }

  calcPos(x: number, scale: number): number {
    if (x < 0) {
      return (scale * 100 - this.cardWidth(x, scale)) / 2;
    } else if (x > 0) {
      return 100 - (scale * 100 + this.cardWidth(x, scale)) / 2;
    }
    return 100 - (scale * 100 + this.cardWidth(x, scale)) / 2;
  }

  calcScale(x: number): number {
    return 1 - 0.2 * Math.abs(x);
  }

  cardWidth(x: number, scale: number): number {
    return scale * 200;
  }

  showNextCard() {
    this.currentIndex = (this.currentIndex + 1) % this.allAnimes.length;
    this.updateVisibleAnimes();
  }

  showPrevCard() {
    this.currentIndex = (this.currentIndex - 1 + this.allAnimes.length) % this.allAnimes.length;
    this.updateVisibleAnimes();
  }

  startDrag(event: MouseEvent | TouchEvent) {
    this.isDragging = true;
    this.startX = (event instanceof MouseEvent) ? event.pageX : event.touches[0].pageX;
  }

  onDrag(event: MouseEvent | TouchEvent) {
    if (!this.isDragging) return;

    this.currentX = (event instanceof MouseEvent) ? event.pageX : event.touches[0].pageX;
  }

  endDrag() {
    if (!this.isDragging) return;
    this.isDragging = false;

    const diffX = this.currentX - this.startX;

    if (diffX > 50) {
      this.showPrevCard();
    } else if (diffX < -50) {
      this.showNextCard();
    }
  }

  getGenreColor(index: number): string {
    const colors = ['#03a8f5', '#ff5722', '#4CAF50', '#FFC107', '#9C27B0'];
    return colors[index % colors.length];
  }
}

However, the scrolling isn’t working properly right now. The cards don’t move instead, they change only after I release the mouse or lift my finger, so it doesn’t give me the scrolling or swiping effect.

New contributor

Alqatrony is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

LEAVE A COMMENT