スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

animationPrefilter を作成してアニメーションをカスタマイズ

animationPrefilter とは jQuery.Animation()の中で実行される関数で、 jQuery 1.8 から導入されました。 指定したプロパティの正規化後、tweener の実行前に呼び出されます。 おそらく tweener 実行前になんらかの処理を加えたい場合に 利用するのだと思いますが、潜在的にはその後の tween オブジェクトの作成とjQuery.timersへの 関数の登録なども肩代わりすることが可能です(その場合 それらの処理を自力で書く必要がある)。 デフォルトの animationPrefilter に加えて 独自の animationPrefilter を登録して実行させることで アニメーションをカスタマイズすることができます。

主に jQuery 2.0.3 を使って調べたので、他のバージョンでは 当てはまらないことがあるかもしれませんのでご注意下さい。 この機能は現時点で公式にはドキュメント化されていませんので、 将来告知無しで変更される恐れがあります。

animationPrefilter について

animationPrefilter(以降 prefilter)は jQuery.Animation()の第2引数である properties オブジェクト(アニメーションさせるプロパティと その目的値が指定されているオブジェクト)のクローンを 正規化した後に実行されます。 コンテキスト(this)は animation オブジェクトで、 引数としてアニメーションさせる要素(DOM 要素)、 正規化後の properties オブジェクト(以降 props)、 animation.optsオブジェクト(以降 opts)が 渡されます。 (animation オブジェクトはアニメーションに関する情報を 格納したオブジェクトです。 .animate() のページに概要が書いてあります)

// イメージとして下のような呼ばれ方をする
prefilter.call( animation, elem, props, animation.opts );

正規化後の props ではプロパティ名がキャメルケースになっています。 また、jQuery.cssHooksexpand関数が 登録されているプロパティ(デフォルトでは margin, padding, borderWidth)は展開されています。 (例えばmargin: "10px 20px 30px 40px"と指定していた 場合はmarginTop: "10px", marginRight: "20px", marginBottom: "30px", marginLeft: "40px" に展開されている)

prefilter は tweener と違いその呼び出しは プロパティごとではなく、 jQuery.Animation()の実行ごとに 登録された prefilter を全て実行しようとします。 デフォルトではデフォルト prefilter のみが登録されていて 実行されます。 prefilter が複数登録されている場合は全て実行しようとしますが、 その実行順序はその登録方法( jQuery.Animation.prefilter()の呼び出し方)に 依存します。 ある prefilter が「trueになるような値」 (truthy な値)を返すとその返り値が jQuery.Animation()の返り値となります。 そのため、独自の prefilter が truthy な値を返す場合は その後のjQuery.Animation()が行うはずだった tween オブジェクト作成、jQuery.timersへの 関数登録に相当する処理などを自前で書く必要があります。

リストに戻る

animationPrefilter の追加方法

prefilter を格納している配列(animationPrefilters)に 直接アクセスすることができないので登録用の関数 jQuery.Animation.prefilter()を使って登録します。

// prefilter を登録する関数
jQuery.Animation.prefilter( callback [, prepend] )
// callback: prefilter 本体
// prepend:  truthy な値なら animationPrefilters に unshift
//           それ以外なら push

引数として、prefilter 本体である関数オブジェクトと その追加方法を渡します。 第2引数に truthy な値を渡すと prefilter を animationPrefilters に対してunshift()で先頭に挿入します。 そうでなければpush()で最後尾に追加します。

登録された prefilter の実行順序は animationPrefilters の 先頭から順に実行されます。それを踏まえて先頭に追加する (デフォルト prefilter の前に実行する)か最後尾に追加する (デフォルト prefilter の後に実行する)かを決定します。 デフォルト prefilter の処理内容は

  • opts.queue == false(アニメーションをキューせず 即座に実行するオプション)の時の内部処理
  • 幅・高さ(width, height)のアニメーションの時、 overflow の値をhiddenにする (完了したら元の値に戻す)
  • 目的値が"toggle","show", "hide"の時、ここで tween オブジェクトを作成して 後の tweener では作成されないようにする

のようになっています。

リストに戻る

注意点

ドキュメント化されていない

冒頭で書いたようにドキュメント化されていません。 jQuery のバージョンが進めばこの機能が告知無く変更、 削除されることもありえますので、使用は自己責任でお願いします。

リストに戻る

一度 prefilter を登録したら戻せない

tweener の時と同じ様に 削除用のメソッドが見当たりません。 登録先の配列 animationPrefilters に直接アクセスできないので、 登録した prefilter は削除できません。 工夫すれば削除と同じ意味のことを行うことはできます。

// アクセスできるオブジェクトを経由させて
// 削除のようなことを行う
var hoge = {};
hoge.prefilter = function(elem, props, opts){
  // 実際の prefilter の処理はこっちに書く
};

// 上の実質的な prefilter を呼び出すだけの関数
var myPrefilter = function(elem, props, opts){
  if( hoge.prefilter ){
    return hoge.prefilter.call(this, elem, props, opts);
  }
};

// 登録は myPrefilter の方
jQuery.Animation.prefilter( myPrefilter );

// 削除する時は hoge.prefilter を false になるような値にする
// そうすれば何もしない関数が実行されるだけになり、
// 削除と同様の意味になる
hoge.prefilter = false;
リストに戻る

使用例

jQuery Inline Easing プラグインが animationPrefilter を使っていますので そのコードを紹介します。 easing 関数を新規作成して使うにはあらかじめ jQuery.easingオブジェクトに 登録しておく必要があるのですが、このプラグインは その必要を無くして無名関数で動的に指定できるようにします。 (コメントは全て自分が追加したものです)

// 著作権表示を Github のページ
// ( https://github.com/gnarf/jquery-inline-easing )から転載
// 2013/11/08 時点

// Copyright (c) 2013 Corey Frang
// Licensed under the MIT license.

(function( jQuery ) {

// 一意な easing 名を作成するための変数
var uuid = 0;
var inlineEasingUUID = "inlineEasingUUID";

jQuery.Animation.prefilter(function( element, properties, options ) {
  var prop;
  var replaced = [];
  var easing = options.specialEasing;

  // value が関数なら jQuery.easing オブジェクトに
  // 登録しその名前を返す。それ以外ならそのまま返す
  function mapFn( value ) {
    var stringName;
    if ( jQuery.type( value ) === 'function' ) {
      // 一意な easing 名を作成して登録する
      stringName =
        inlineEasingUUID + ( uuid++ );
      jQuery.easing[ stringName ] = value;
      // アニメーション終了後 jQuery.easing から
      // 登録した関数を取り除くために記憶しておく
      replaced.push( stringName );
    }
    return stringName || value;
  }

  // easing の値が関数なら jQuery.easing オブジェクトに
  // 登録しその登録名を値にする
  for( prop in easing ) {
    easing[ prop ] = mapFn( easing[ prop ] );
  }
  options.easing = mapFn( options.easing );

  // アニメーション終了後に jQuery.easing から
  // 登録した関数を取り除くようにする
  if ( replaced.length ) {
    this.always(function() {
      for ( prop = 0; prop < replaced.length; prop++ ) {
        delete jQuery.easing[ replaced[ prop ] ];
      }
    });
  }
});


}( jQuery ));

以上のようにアニメーションをカスタマイズすると、 以下のように easing が関数オブジェクトで動的に指定できます。

// 上のカスタマイズ後

$("#target")
  .animate({ marginLeft: "+=500px" },
           { duration: 1000,
             // デフォルトでは文字列でしか指定できないが
             // 関数オブジェクトで指定できる
             easing: function( p ){ 
               return p * p * p;
             }
           });

これは例として適当に書いたものですので、 テストをしていません。ご注意下さい。

リストに戻る

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。