0

I want to create a sliding background image much like what you see at this site: https://chucklefish.org/. Notice how every few seconds a new background image slides in.

I want to do this using Angular's animation module.

Typescript

import { Component, HostBinding, OnInit } from '@angular/core';
import {
  trigger,
  state,
  style,
  animate,
  transition,
  // ...
} from '@angular/animations';
@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css'],
  animations: [
    trigger('slidingPictures',[
      state('game1',style({
        background:"url(../assets/images/game1.jpg)"
      })),
      state('game2',style({
        background:"url(../assets/images/game2.png)"
      })),
      state('game3',style({
        background:"url(../assets/images/game3.jpg)"
      })),
      transition('game1=>game2',[
        animate('1s',
        style (
          {
            transform: 'translateX(-100%)',

          }
          ))
      ]),
      transition('game2=>game3',[
        animate('1s',style({
          transform: 'translateX(-100%)',

        }))
      ]),
      transition('game3=>game1',[
        animate('1s',style({transform: 'translateX(-100%)'}))
      ])

    ]),
  ]
})
export class HomeComponent implements OnInit {
  game:string;
  gameIndex:number;
  games:string[];
  constructor() { 
    this.gameIndex = 0;

    this.games = ['game1','game2','game3'];
    this.game = this.games[this.gameIndex];

    setInterval(() => this.rotatingBackground(), 5000);

  }

  ngOnInit() {


  }

  rotatingBackground():any {
    console.log(this.gameIndex);
    this.game = this.games[this.gameIndex];
    this.gameIndex++;
    if(this.gameIndex >= this.games.length) {
      this.gameIndex = 0;
    }
    console.log(this.game);
  }


}

Right now how code works is that there are images that slide to the left but while they slide to the left there is a white background. I would like the new image to slide in from the right at the same time.

Peter
  • 143
  • 2
  • 11

1 Answers1

1

if you need see at time two images, you need almost two divs (*). Simulate a background it's easy with a div with .css

.background {
  position:absolute;
  top:0;
  left:0;
  width:100%;
  height:100%;
  z-index:-1;
}

If you has seerals div, you can simulate simple with a clasic animation "flyInOut"

  animations: [
    trigger('flyInOut', [
      state('in', style({ transform: 'translateX(0)' })),
      transition('void => *', [
        style({ transform: 'translateX(-100%)' }),
        animate(100)
      ]),
      transition('* => void', [
        animate(100, style({ transform: 'translateX(100%)' }))
      ])
    ])
  ]

I prefer subscribe to interval not create a setInterval

interval(5000).subscribe(() => {
  this.index = (this.index + 1) % this.numImages
})

See an example in stackblitz

Update 2 Really I don't know how makea a preloader of the images. So, my best try is repeat the divs, the last with height and with equal 0

<ng-container *ngFor="let i of [0,1,2,3]">
    <div *ngIf="i==index && !loading" [@flyInOut] [ngClass]="'background div'+i">
    </div>
</ng-container>

<ng-container *ngIf="loading">
    <div style="with:0;height:0" *ngFor="let i of [1,2,3]" [ngClass]="'background div'+i">
    </div>
    <div [@flyInOut] class="background div0"></div>
</ng-container>

And in the interval

    interval(5000).subscribe(() => {
      this.loading=false;
      this.index = (this.index + 1) % this.numImages
    })

Updated 3 bassed in the answer to this question on stackoverflow I sugesst change the ngOnInit like

  index: number = 0;
  numImages: number = 4;
  imagesLoaded: number = 0;
  loading: boolean = true;
  imagesUrl = [
    "https://picsum.photos/id/402/2500/1667",
    "https://picsum.photos/id/301/2500/1667",
    "https://picsum.photos/id/302/2500/1667",
    "https://picsum.photos/id/400/2500/1667"]

  ngOnInit() {
    //preload the images
    this.imagesUrl.forEach((x, index) => {
      const image = new Image();
      image.onload = (() => {
        this.imagesLoaded++;
        this.loading = (this.imagesLoaded != this.numImages)
      })
      image.src = x
    })

    interval(5000).subscribe(() => {
      if (!this.loading)
         this.index = (this.index + 1) % this.numImages
    })
  }

(*)Other option is has a large background composite of all the images one each next to another and animate the background-position

Eliseo
  • 50,109
  • 4
  • 29
  • 67