Rekapi ext/css-animate/rekapi.css-animate.context.js

CSSRenderer

method
Kapi.CSSRenderer()
  • @param: {Kapi}kapi
  • @constructor:

Description

The CSSRenderer module allows you to run a Rekapi animation as a CSS @keyframe animation. Standard Rekapi animations are powered by JavaScript, but in many cases using CSS @keyframes is smoother.

Note! This is an experimental feature. If you encounter any issues, please report them with the Rekapi issue tracker.

Advantages of playing an animation with CSS @keyframes instead of JavaScript:

  • Smoother animations in modern browsers (particularly noticeable in Webkit and mobile browsers).
  • The JavaScript thread is freed from performing animation updates, resulting in more resources for other logic.

Disadvantages of CSS @keyframes:

  • No start/stop/goto control - once the animation runs, it runs from start to finish.
  • Prerending animations can take a non-trivial amount of time, so you may have to be clever with how to spend the cycles to do it.
  • Currently, no Kapi events can be bound to CSS animations.

This module requires both the toCSS and Kapi.DOMActor modules (they are included in the standard Rekapi distribution). Functionally, CSSRenderer works by prerendering a CSS animation and injecting it into the DOM. You'll never have to call the CSSRenderer constructor explicitly, that is done for you when a Rekapi instance is initialized.

An advantage of this module is that CSS animations are not always available, but JavaScript animations are. Keyframes are defined the same way, but you can choose what method of animation is appropriate at runtime:

 var kapi = new Kapi();
 var actor = new Kapi.DOMActor(document.getElementById('actor-1'));

 kapi.addActor(actor);
 actor.keyframe(0,    { left: '0px'   });
 actor.keyframe(1000, { left: '250px' }, 'easeOutQuad');

 // Feature detect for @keyframe support
 if (kapi.css.canAnimateWithCSS()) {
   kapi.css.play();
 } else {
   kapi.play();
 }

Example

Source

Kapi.CSSRenderer = function (kapi) {
    if (!Kapi.DOMActor && !Kapi.prototype.toCSS) {
      throw 'CSSRenderer requires the DOMActor and toCSS modules.';
    }

    this.kapi = kapi;

    // @private {number}
    this._playTimestamp = null;

    // @private {string}
    this._cachedCSS = null;

    // The HTMLStyleElement that gets injected into the DOM.
    // @private {HTMLStyleElement)
    this._styleElement = null;

    // @private {number}
    this._stopSetTimeoutHandle = null;

    kapi.on('timelineModified', _.bind(function () {
      this._cachedCSS = null;
    }, this));

    return this;
  };
  var CSSRenderer = Kapi.CSSRenderer;

canAnimateWithCSS

method
CSSRenderer.prototype.canAnimateWithCSS()
  • @return: {boolean}

Description

Whether or not the browser supports CSS @keyframe animations.

Source

CSSRenderer.prototype.canAnimateWithCSS = function () {
    return !!getVendorPrefix();
  };

prerender

method
CSSRenderer.prototype.prerender()
  • @param: {number=}opt_iterationsHow many times the animation should loop. This can be null or 0 if you want to loop the animation endlessly but also specify a value for opt_fps.
  • @param: {number=}opt_fpsHow many @keyframes to prerender per second of the animation. The higher this number, the smoother the CSS animation will be, but the longer it will take to prerender. The default value is 30, and you should not need to go higher than 60.
  • @return: {string}The prerendered CSS string. You likely won't need this, as it is also cached internally.

Description

Prerender and cache CSS so that it is ready to be used when it is needed in the future. The function signature is identical to CSSRenderer#play. This is necessary to run a CSS animation and will be called for you if you don't call it manually, but calling this ahead of time (such as on page load) will prevent any perceived lag when a CSS animation starts. The prerendered animation is cached for reuse until the timeline is modified (by adding, removing or modifying a keyframe).

Source

CSSRenderer.prototype.prerender = function (opt_iterations, opt_fps) {
    return this._cachedCSS = this.kapi.toCSS({
      'vendors': [getVendorPrefix()]
      ,'fps': opt_fps
      ,'iterations': opt_iterations
    });
  };

play

method
CSSRenderer.prototype.play()
  • @param: {number=}opt_iterationsHow many times the animation should loop. This can be null or 0 if you want to loop the animation endlessly but also specify a value for opt_fps.
  • @param: {number=}opt_fpsHow many @keyframes to prerender per second of the animation. The higher this number, the smoother the CSS animation will be, but the longer it will take to prerender. The default value is 30, and you should not need to go higher than 60.

Description

Play the Rekapi animation as a @keyframe animation.

Source

CSSRenderer.prototype.play = function (opt_iterations, opt_fps) {
    if (this.isPlaying()) {
      this.stop();
    }

    var css = this._cachedCSS || this.prerender.apply(this, arguments);
    this._styleElement = injectStyle(css);
    this._playTimestamp = now();

    if (navigator.userAgent.match(/Presto/)) {
      forceStyleInjection(this.kapi);
    }

    if (opt_iterations) {
      var animationLength = (opt_iterations * this.kapi.animationLength());
      this._stopSetTimeoutHandle = setTimeout(
          _.bind(this.stop, this, true),
          animationLength + INJECTED_STYLE_REMOVAL_BUFFER_MS);
    }

    fireEvent(this.kapi, 'play', _);
  };

stop

method
CSSRenderer.prototype.stop()
  • @param: {boolean}opt_goToEndIf true, set the elements to their target position (in other words, skip to the end of the animation). If false or omitted, set the Actor elements to stay in their current position.

Description

Stop a CSS animation. This also removes any <style> elements that were dynamically injected into the DOM. This method sets inline styles on Actor elements to stay either in their target or current position.

Source

CSSRenderer.prototype.stop = function (opt_goToEnd) {
    if (this.isPlaying()) {
      clearTimeout(this._stopSetTimeoutHandle);

      // Forces a style update in WebKit/Presto
      this._styleElement.innerHTML = '';

      document.head.removeChild(this._styleElement);
      this._styleElement = null;

      var updateTime;
      if (opt_goToEnd) {
        updateTime = this.kapi.animationLength();
      } else {
        updateTime = (now() - this._playTimestamp)
            % this.kapi.animationLength();
      }

      this.kapi.update(updateTime);
      fireEvent(this.kapi, 'stop', _);
    }
  };

isPlaying

method
CSSRenderer.prototype.isPlaying()
  • @return: {boolean}

Description

Whether or not a CSS animation is running.

Source

CSSRenderer.prototype.isPlaying = function () {
    return !!this._styleElement;
  };

});