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.cssHooks
のexpand
関数が
登録されているプロパティ(デフォルトでは
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;
}
});
これは例として適当に書いたものですので、 テストをしていません。ご注意下さい。
リストに戻る