Animations in AngularJS



Animations in AngularJS

1 4


nganimate-google-slides


On Github matsko / nganimate-google-slides

Animations in AngularJS

Supercharge your ng code with some high level animations

By: Matias Niemelä

@yearofmoo

http://www.yearofmoo.com

Eight major AngularJS articles.

Great resource to learn about AngularJS.

Slides

http://yom.nu/ng-ani-goog-slides

Animations on the web (the good)

Solid CSS3 animation browser support

Great JS animations libraries available on the web

Hardware-accelerated animations

DOM APIs are getting better for animations

Animations on the web (the bad)

Difficult to properly sync animations together

CSS animation detection is tricky

Animations are coupled with HTML code

Very little isolation from the rest of the application

Animations before ngAnimate

ngClass was your best bet

No way to hook into existing ng directives

You can still make your own directives

Too much of your own JS code is required

HTML code may change due to the presence of animations

ngAnimate

Introduced in AngularJS 1.1.4

Enhanced in AngularJS 1.1.5

Remastered & Supercharged in 1.2

Exists within a separate module

ngAnimate Features

Supports CSS3 transition/keyframe animations natively

JavaScript callbacks are also supported

Automatically manages all state within animation events

Various existing ng directives are animation aware

Easy way to disable / enable animations

Benefits of using ngAnimate

Uses only CSS classes to reference animations

All animation code is isolated

CSS and JS code is plug and play

Handles all sniffing, detection and computations for you

Highly performant

Basic Use

Include angular-animate.js into your application

Set ngAnimate as a module dep

Place a CSS class in your HTML code to reference the animation(s)

Create an animation using CSS or JavaScript using the CSS class name

CSS3 Transition Animations

Two CSS classes required.

/* starting styles */
.my-class.ng-EVENT {
  transition:0.5s linear all;
  transform:scale(0.1);
}

/* destination styles */
.my-class.ng-EVENT.ng-EVENT-active {
  transform:scale(1.5);
}

CSS3 Keyframe Animations

Only one CSS class required.

/* animation keyframe CSS */
.my-class.ng-EVENT {
  animation:0.5s my_animation;
}

/* animation CSS (from & to) */
@keyframes my_animation {
  from { background:blue; }
  to { background:red; }
}

More Info about CSS transitions/animations

Checks CSS classes each time on an element

CSS styles can be changed via media queries

An additional CSS stylesheet can be added/removed

JavaScript Animations

Defined just like a service is defined

ngModule.animation('.my-class', function(inject) {
  return {
    EVENT : function(element, done) {
      /* run your animation using your own JS code */
      runMyAnimation(element, done);

      return function(cancelled) {
        closeMyAnimation(element);
      };
    }
  };
});

Animation-aware Directives

ngAnimate actives the following directives

Directive Events ngRepeat enter, move, leave ngView enter, leave ngSwitch, ngInclude, ngIf enter, leave ngClass addClass, removeClass ngHide, ngShow addClass('.ng-hide') removeClass('.ng-hide')

Let's put something together

http://yom.nu/ng-ani-google-simple

http://yom.nu/ng-ani-goog-code

Steps involved in Animation

1. A scope change happens and some directive does its thing

2. A DOM operation is called which is handled by the $animate service

3. An extra digest occurs or the animation starts right away

4. Checks for anything disabled

5. Grabs the CSS classes and triggers the animations that match that CSS class

6. CSS transitions / keyframes + JS animations are triggered one by one

7. getComputedStyle -> animate CSS transitions/animations

8. Close the animation -> perform any required DOM operations

Animating ngView

Let's use CSS transitions: enter, leave

.view.ng-enter {
  transition:1s linear all; 
  position:relative;
  left:100px;
  opacity:0;
}
.view.ng-enter.ng-enter-active {
  opacity:1;
  left:0px;
}
.view.ng-leave {
  transition:1s linear all; 
  position:relative;
  opacity:1;
  left:0px;
}
.view.ng-leave.ng-leave-active {
  opacity:0;
  left:-100px;
}

Animating ngRepeat

Let's use CSS3 animations: enter, leave, move

<div ng-repeat="item in items" class="repeater"></div>

.repeater.ng-enter {
  animation:
    repeater_enter 1s;
}
@keyframes repeater_enter {
  from { opacity:0; }
  to { opacity:1; }
}
.repeater.ng-leave {
  animation:
    repeater_leave 1s;
}
@keyframes repeater_leave {
  from { opacity:1; }
  to { opacity:0; }
}
.repeater.ng-move {
  animation:
    repeater_move 1s;
}
@keyframes repeater_move {
  from { opacity:1; }
  to { opacity:0; }
}

Animating ngInclude

Let's use JS Animations enter, leave

<div ng-include="tpl" class="slide"></div>

myModule.animation('.slide', function() {
  return {
    enter : function(element, done) {
      $(element)
        .css({ opacity:0 })
        .animate({ opacity:1 }, done);
    },
    //...
leave : function(element, done) {
      $(element).animate({
        opacity:0
      }, done);
    }
  };
});

Animating ngShow / ngHide

Let's use JS Animations ng-hide-remove, ng-hide-add

<div ng-hide="bool" class="show-hide"></div>

.show-hide.ng-hide-add {
  transition:0.5s linear all;
  opacity:1;
}
.show-hide.ng-hide-add
  .ng-hide-add-active {

  opacity:0;
}
.show-hide.ng-hide-remove {
  transition:0.5s linear all;
  opacity:0;
}
.show-hide.ng-hide-remove
  .ng-hide-remove-active {

  opacity:1;
}

Fully animating application

http://yom.nu/ng-ani-goog-advanced

$animate

Used to trigger animations inside directives

Skips all animations when disabled or when ngAnimate is not included

Event class="klass ng-EVENT" enter $animate.enter(element, parent, after, done) leave $animate.leave(element, done) move $animate.move(element, parent, after, done) addClass $animate.addClass(element, className, done) removeClass $animate.removeClass(element, className, done) enabled $animate.enabled(bool)

$animate under the hood

Skips the former animation is a previous animation is called

Skips all child animations when a parent animation is animating

Caches subsequent getComputedStyle lookups to speed animations

Queues all animations into as few reflows as possible

Testing (sync)

Test to see that an animation gets fired

1. Create a JS animation within your spec

2. Create a fake CSS style and examine the generated CSS classes

it('should animate', function() {
  var interceptedClass;
  module(function($animateProvider) {
    $animateProvider.register('.animated', function() {
      return {
        addClass : function(element, className, done) {
          interceptedClass = className;
          done();
        }
      };
    });
  });
  inject(function($compile, $rootScope, $rootElement) {
    var element = $compile('<div class="animated" ng-class="{on:on}"></div>')($rootScope);
    $rootElement.append(element);

    $rootScope.on = true;
    $rootScope.$digest();

    expect(interceptedClass).toBe('on');
  });
});

Testing (async)

Wait for the entire duration of the animation and compare the styles

Use within the tests if possible to avoid async calls

New plans (post 1.2)

Improve the compatibility of CSS code

Provide a better API for JS animations

Staggering animations in both CSS AND JS

Thank you!

Please use and experiment with animations so that we can make this tool better

@yearofmoo

Feel free to contact me via matias@yearofmoo.com