女子小学生と××したい

Webフロントエンド界のゴミクソメンヘラであり続けたい

jQueryのanimate関数を自作してみた(超未完、追記あり)


はい。以上です。

















ではなく。解説します。
最近までjQueryでしかjs書けなくてほんとクソだなー早くフロントやめて死ねばいいのにって思ってたのでjQueryの代替品を作っているかるねです。
で、defferedとajaxとanimateとquerySelector以外は大体作り終えたので、んじゃanimateやるかーってなったとこです。って書いたけど残ってる奴らが強敵ばかりだな………
ま、まぁいいか。中途animateの説明しますね。

まず始めに、このanim関数はjQueryのanimate関数と比べてまだ色々不備を抱えています。そりゃあね。半日でべべべっと組んだわけですし。で、現時点で分かってる不備は以下の通り

  • メソッドチェーンによるコールバック登録
  • margin, paddingの複数値設定への対応
  • easing(追記あり)
  • 色を指定する16進のtransition(jQueryのanimateは非対応。プラグインあり)

こんな感じか。実用する上で致命的なのはeasing、次にmargin,padding、次いでコールバック登録で、色のtransitionかしら。今はlinearしかできないからほんと使い物にならん。早くeasing実装せねば

この関数を機能分割すると

  1. 引数で与えられたプロパティから接尾詞(今のところpxのみ)の有無を認識する
  2. 該当プロパティの初期値の設定
  3. forとsetTimeoutでstyleを書き換える

だけです。初期化付近は読めば分かるので、メイン部分の3.について

// main function
function anim(el,prop,duration,easing,callback){
    cnt = parseInt(duration/timerInterval,10),
    index = 0;

    // initialize (suffix,get value,...)
    for(var key in prop){
        crnt[key] = setCrnt(el,key);
        obj = setSuffix(crnt[key],prop[key]);
        crnt[key] = obj.crnt;
        start[key] = obj.crnt;
        prop[key] = obj.goal;
        delta[key] = obj.delta;
        suffix[key] = obj.suffix;
    }

    // animate loop
    for(var i=0;i<cnt;i++){
        window.setTimeout(function(){
            for(var key in prop){
                // set property
                crnt[key] += delta[key]/cnt;
                if(easing){
                    el.style[key] = calcEasing(index,cnt,start[key],crnt[key],prop[key]) + suffix[key];
                }else{
                    el.style[key] = crnt[key] + suffix[key];
                }
            }
            
            // when complete animate
            if(++index>=cnt){
                for(key in prop){
                    el.style[key] = prop[key] + suffix[key];
                }
                if(callback){callback();}
            }
        },timerInterval*i);
    }
}

引数は

  • el:対象となるDOM
  • prop: 変化させるプロパティをkey、目標値をvalueとするobject。
{width: '100px',height: '300px',opacity: '0.5',fontSize: '30px'}

みたいに渡す

  • duration: アニメーション時間(msec)
  • easing: 今のところeasingは1種類しかないので、booleanで適用の有無を指定する。
  • callback: アニメーション完了時に実行する関数を指定する。

処理の順番としては

  1. durationをtimerInterval(1000msecをリフレッシュレート(コードでは60)で割った値)で割り、ループの回数を計算する
  2. propの中を見て、接尾詞の有無や初期値の設定を行う
  3. cnt回のループ内でsetTimeoutを設定する
  4. 現在のプロパティ値(crnt)に、目標値との差分(delta)をループ回数(cnt)で割った値を加算し、styleに設定していく(easingの説明は一旦省きます)
  5. 4.を、prop内のkeyの数だけ実行する。これをループ内の処理としています
  6. forループの完了を観測したら、styleの値を目標値に強制的に設定する。これは、4.で計算したdeltaを加算していくだけでは正確に目標値に到達しないことがあるため。例えば、初期値0、目標値1、ループ回数3ではループ完了時の値は0.99999....となる。これを丸めるために最後は手動で値を設定する
  7. コールバック関数が存在していればそれを実行する

といった感じです。
メインループ周りは今のところシンプルな実装になっていると思っています、自分では。
ひとまずはこれで最低限の機能は満たしているように見えます。
とは言え、実用に至るにはやはりeasingがないと使えない。
けれども僕は数学に滅法弱いので、jQuery.easingを流用する方法をさぐりながら今週を過ごそうと思います。色々説明不足ですが何かあったらコメントなりjsdo.itの方でお願いします。

お腹減ったー

追記(2013/04/09 16:55)
jQuery.easingを移行できました。引数easingにjQuery.easingのような種類を表すstringを入れると変化量が変わるように実装しました。ただ、bounce系だけ上手く実装できず、調査中です