Categories
Angular JavaScript TypeScript

Angular Animation Callbacks and Key Frames

Spread the love

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we look at animation callback and keyframes.

Animation Callbacks

The animation trigger emits callbacks when it starts and when it finishes.

For example, we can log the value of the event by writing the following code:

app.component.ts :

import { Component, HostBinding } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,  
  state  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      state(  
        "true",  
        style({ height: "200px", opacity: 1, backgroundColor: "yellow" })  
      ),  
      state(  
        "false",  
        style({ height: "100px", opacity: 0.5, backgroundColor: "green" })  
      ),  
      transition("false <=> true", animate(500))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div  
  [@openClose]="show ? true: false"  
  (@openClose.start)="onAnimationEvent($event)"  
  (@openClose.done)="onAnimationEvent($event)"  
>  
  {{show ? 'foo' : ''}}  
</div>

In the code above, we have:

(@openClose.start)="onAnimationEvent($event)"  
(@openClose.done)="onAnimationEvent($event)"

to call the onAnimationEvent callback when the animation begins and ends respectively.

Then in our onAnimationEvent callback, we log the content of the event parameter.

It’s useful for debugging since it provides information about the states and elements of the animation.

Keyframes

We can add keyframes to our animation to create animations that are more complex than 2 stage animations.

For example, we can write the following:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('2s', keyframes([  
          style({ backgroundColor: 'blue' }),  
          style({ backgroundColor: 'red' }),  
          style({ backgroundColor: 'orange' })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we add keyframes with different styles in AppComponent .

They’ll run in the order that they’re listed for the forward state transition and reverse for the reverse state transition.

Then when we click Toggle, we’ll see the color changes as the text changes.

Offset

Keyframes include an offset that defines the point in the animation where each style change occurs.

Offsets are relative measures from zero to one. They mark the beginning and end of the animation.

These are optional. Offsets are automatically assigned when they’re omitted.

For example, we can assign offsets as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('2s', keyframes([  
          style({ backgroundColor: 'blue', offset: 0 }),  
          style({ backgroundColor: 'red', offset: 0.6 }),  
          style({ backgroundColor: 'orange', offset: 1 })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we added offset properties to our style argument objects to change the timing of the color changes.

The color changes should shift slightly in timing compared to before.

Keyframes with a Pulsation

We can use keyframes to create a pulse effect by defining styles at a specific offset throughout the animation.

To add them, we can change the opacity of the keyframes as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,    
  keyframes  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      transition('true <=> false', [  
        animate('1s', keyframes ( [  
          style({ opacity: 0.1, offset: 0.1 }),  
          style({ opacity: 0.6, offset: 0.2 }),  
          style({ opacity: 1,   offset: 0.5 }),  
          style({ opacity: 0.2, offset: 0.7 })  
        ]))  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we have the style argument objects that have the opacity and offset properties.

The opacity difference will create a pulsating effect.

The offset will change the timing of the opacity changes.

Then when we click Toggle, we should see the pulsating effect.

Automatic Property Calculation with Wildcards

We can set CSS style properties to a wildcard to do automatic calculations.

For example, we can use wildcards as follows:

app.component.ts :

import { Component } from "@angular/core";  
import {  
  trigger,  
  transition,  
  style,  
  animate,  
  state  
} from "@angular/animations";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"],  
  animations: [  
    trigger("openClose", [  
      state("in", style({ height: "*" })),  
      transition("true => false", [  
        style({ height: "*", backgroundColor: "pink" }),  
        animate(250, style({ height: 0 }))  
      ]),  
      transition("false => true", [  
        style({ height: "*", backgroundColor: "yellow" }),  
        animate(250, style({ height: 0 }))  
      ])  
    ])  
  ]  
})  
export class AppComponent {  
  onAnimationEvent(event: AnimationEvent) {  
    console.log(event);  
  }  
}

app.component.html :

<button (click)="show = !show">Toggle</button>  
<div [@openClose]="show ? true: false">  
  {{show ? 'foo' : 'bar'}}  
</div>

In the code above, we set the height of the styles to a wildcard because we don’t want to set the height to a fixed height.

Then when we click Toggle, we see the color box grow and shrink as the animation runs.

Conclusion

We can add callbacks to our animation to debug our animations since we can log the values there.

To make more complex animations, we can use keyframes.

Offsets can be used to change the timing of the keyframes of the animation.

We can use wildcards to automatically set CSS style values.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *