クロージャ(3)cssアニメとの連携(3)概要transformを利用したアニメ前回、ハードウェアアクセラレーションが効くtransitionとtransformを利用したcssアニメを学びました。このtransformは移動先(座標)を指定するのではなく移動量を指定するため、目的の座標に移動させるには少し工夫が必要となります。ここではtransformを利用して目的の座標へ移動するサンプルを完成させ、さらに移動が完了したら処理を実行できるようにしたいと思います。追記:2014.6/29iOS6ではtransitionにもベンダープリフィックスの-webkit-が必要ということが判明したので、記事とサンプル内のソースを変更しました。私が最初にtransfromを利用したアニメを作成した時にハマってしまった部分があります。間違いを繰り返さないために、まずは失敗例を確認します。サンプル(cssAnime3/01.html)のソースを開いて、body内の構成とcssの設定は前回のサンプル(cssAnime2/03b.html)から変更がないことを確認してください。jQueryは大きく変更されています。transformは移動量を指定しなければならないので、以下の様な式で目的座標と現在の座標から移動量を算出しなければなりません。現在の座標が200pxで目的座標が300pxなら、移動量は100pxとなります。pageYプロパティを利用します。positionメソッドで取得できます(下表2行目)。あとは上記の式に合わせて移動量moveXとmoveYを算出(3,4行目)して5行目でtranslateの値として利用するようにしました。myPos.top;$("div").css("-webkit-transform","translate("+moveX+"px,"+moveY+"px)");});考え方は間違っていないと思うのですが実際にdocument上をクリックしても、その位置にdiv要素が移動しません。そこでもっとシンプルなサンプルで検証することにしました。サンプル(cssAnime3/01b.html)を開いてjQueryが以下の様に変更されているのを確認してください。このサンプルではdiv要素をクリックするとX方向に100px移動するだけのサンプルです。$("div").click(function(eo){$("div").css("-webkit-transform","translate(100px,0px)");});私の最初の予想ではdiv要素をクリックする度に右に100px移動すると考えていたのですが、実際にクリックすると最初の1回は移動しますが、2回目以降は移動しません。この結果から、基準となる座標は「現在の座標」ではなく「最初に配置された座標」ということが分かりました。移動量を算出する式は以下の様に修正しなければなりません。何回場所を移動しても、基となる座標は最初に配置した座標です。いうことでcssAnime3/01.htmlの様にクリックされる度に現在の座標を取得するのではなく、最初に配置された座標を利用するように変更します。サンプル(cssAnime3/02.html)を開いて、jQueryが以下の様に変更されているのを確認してください。positionメソッドを利用して座標を取得する部分を、クリックのイベントハンドラの外に出しただけです。これでクリックする毎に現在の座標を取得するのではなく、最初に配置した座標を利用することになります。myPos.top;$("div").css("-webkit-transform","translate("+moveX+"px,"+moveY+"px)");});結果としてクリックされた場所に移動するようになりました。アプリの作成では移動が完了したら、何かしらの処理を実行したいケースが多くあります。次はコールバックの設定について説明します。アニメが終わったら処理を実行する(1)animateメソッドは引数にfunctionを設定することで、アニメが完了したら実行する処理を簡単に設定できます。transitionを利用したアニメではこのようなコールバックを指定することはできませんが、transitionendというイベントが利用できるので、これをjQueryで利用して対応します。transitionendについては以下のサイトでも説明されています。使用」ただし新しいブラウザでも対応していないためベンダープリフィックスが必要となり、イベント名はwebkitTransitionEndとなります(サンプルはsafariかchoromeで確認してください)。サンプル(cssAnime3/03.html)を開いてjQueryが以下の様に変更されているのを確認してください。cssメソッドで背景色を変更(4行目)するようにしています。myPos.top;$("div").css("-webkit-transform","translate("+moveX+"px,"+moveY+"px)").on("webkitTransitionEnd",function(){$("div").css("background-color","#F9F");});実際にdocumentをクリックしてdiv要素を移動させ、移動が終わったらdiv要素の背景色がピンクに変わる事を確認して下さい。setTimeoutを利用する前述のサンプルはPCでは問題ないようなのですが、Android端末でイベントが発生しないバグがあります。私がこのアプリを作成した際にもたくさん発生し、Androidでは実質webkitTransitionEndは利用できないと判断しました。日本語圏では報告例がないのですが、英語では報告例が幾つかあります。fire」ブラウザ側の問題なようなので、webkitTransitionEndは利用せずにsetTimeoutを利用して問題を回避するようにしました。サンプル(cssAnime3/04.html)を開いて、jQueryが以下の様に変更されているのを確認してください。setTimeoutを利用して背景色を変更する処理を実行するようにしました。時間はcssアニメに合わせて500ミリ秒にしています。myPos.top;$("div").css("-webkit-transform","translate("+moveX+"px,"+moveY+"px)");setTimeout('$("div").css("background-color","#F9F");',500);});実際にdocumentをクリックして、div要素が移動した後に背景色がピンクになることを確認して下さい。このサンプルは分かりやすいようにdiv要素が1つしかありません。実際にアプリ作成する時は複数の要素を管理しなければなりません。次項では複数のdiv要素があるときに、どのようにsetTimeoutを利用するかを説明します。アニメが終わったら処理を実行する(2)まずはsetTimeoutを利用せずに複数のdiv要素をアニメさせるサンプルを確認します。サンプル(cssAnime3/05.html)を開いてbody内にdiv要素が5つ有ることを確認して下さい。続いてcssは以下の様に設定されています。配置に関する設定が異なるだけでアニメの設定は変更有りません。div{position:relative;width:50px;height:50px;margin:10px;background-color:#6CF;-webkit-transition-property:-webkit-transform;-webkit-transition-duration:0.5s;}jQueryは以下の様に記述され、div要素がクリックされたらクリックされたdiv要素(this)をアニメさせるようにしています。アニメはシンプルにX座標を500px移動させるだけです。$("div").click(function(eo){$(this).css("-webkit-transform","translate(500px,0px)");});実際にdiv要素をクリックして、クリックした要素だけがアニメで移動することを確認して下さい。次はsetTimeoutを追加するのですが、setTimeout内ではthisを利用することはできません。サンプル(cssAnime3/06.html)を開いてjQueryが以下の様に変更されているのを確認してください。$("div").click(function(eo){$(this).css("-webkit-transform","translate(500px,0px)");setTimeout(function(){$(this).css("background-color","#F9F");},500);});考え方としては正しいのですが、setTimeout内でthisは利用できないのでアニメが完了しても色は変わりません。簡単な解決法としてはthisを別の変数に代入しておき、それを利用することです。サンプル(cssAnime3/06b.html)を開いてjQueryが以下の様に変更されているのを確認してください。2行目でthisの要素を変数myObjに代入し、それを5行目のsetTimeout内の処理で利用するだけです。実際にdiv要素をクリックしてアニメの後に色が変わることを確認して下さい。$(this);myObj.css("-webkit-transform","translate(500px,0px)");setTimeout(function(){myObj.css("background-color","#F9F");},500);});setTimeoutを利用する場合のデメリットとして、アニメの長さを変更する度にsetTimeoutの時間指定も変更しなければいけない点です。最後にアニメの時間もcssで設定するのではなく、javaScriptで設定するようにします。サンプル(cssAnime3/07.html)を開いてcssでアニメの長さ(transition-duration)が設定されていないことを確認して下さい。div{position:relative;width:50px;height:50px;margin:10px;background-color:#6CF;-webkit-transition-property:-webkit-transform;}続いてjQueryを確認します。1行目でアニメの長さ(ミリ秒)を変数speedに代入します。cssメソッドの値として変数speedを利用してアニメの長さを設定します。最後にsetTimeoutの時間指定の部分に利用します(8行目)。$(this);myObj.css("-webkit-transform","translate(500px,0px)");setTimeout(function(){myObj.css("background-color","#F9F");},speed);});こうすることでアニメの長さを変更する際にcssアニメとsetTimeoutの値が同時に変わるため修正のミスが少なくなります。これでcssアニメの長さとjQueryの連携の説明を終わります。cssアニメは利用できるブラウザが限られているため、現段階ではスマートフォンアプリなどでしか活用する機会は無いと思います。複数のdiv要素のサンプルで、setTimeoutだけでなく座標の管理も行うようなサンプルを作成しました。少々複雑になったのでメモとして記載します。興味のある方はソースを研究してみて下さい。→サンプル(cssAnime3/test01.html)このサンプルではクリーム色の部分(id属性cardArea)をクリックするとカード(class属性card)をクリックした位置に生成します。カードをクリックすると原点(0,0)にcssアニメで移動します。dataメソッドを利用して記憶し、移動する際にdataに保存した座標を利用して移動量を計算する点です。生成したdiv要素自身に座標位置を記憶させることで管理を簡単にしているのです。