画像 (または要素) を実際の X、Y の位置から X1、Y1 にゆっくりと移動したいと思います。
X と X1 の間の距離が Y と Y1 の間の距離と等しい場合、簡単です。しかし、X の差分が 100px で、Y の差分が 273px だとしたらどうでしょうか。
Javascript は初めてなので、車輪の再発明はしたくありません。その上、私は学んでいるので、jQueryなどを使いたくありません。純粋な JavaScript が必要です。
簡単なスクリプトを提供してください:-)
画像 (または要素) を実際の X、Y の位置から X1、Y1 にゆっくりと移動したいと思います。
X と X1 の間の距離が Y と Y1 の間の距離と等しい場合、簡単です。しかし、X の差分が 100px で、Y の差分が 273px だとしたらどうでしょうか。
Javascript は初めてなので、車輪の再発明はしたくありません。その上、私は学んでいるので、jQueryなどを使いたくありません。純粋な JavaScript が必要です。
簡単なスクリプトを提供してください:-)
1 つの解決策:
function translate( elem, x, y ) {
var left = parseInt( css( elem, 'left' ), 10 ),
top = parseInt( css( elem, 'top' ), 10 ),
dx = left - x,
dy = top - y,
i = 1,
count = 20,
delay = 20;
function loop() {
if ( i >= count ) { return; }
i += 1;
elem.style.left = ( left - ( dx * i / count ) ).toFixed( 0 ) + 'px';
elem.style.top = ( top - ( dy * i / count ) ).toFixed( 0 ) + 'px';
setTimeout( loop, delay );
}
loop();
}
function css( element, property ) {
return window.getComputedStyle( element, null ).getPropertyValue( property );
}
ライブデモ: http://jsfiddle.net/qEVVT/1/
さまざまな機能 (CPU、グラフィックス パワー、コンピューターで実行されているその他の処理) を備えたシステムでスムーズなアニメーションを実行することは、簡単な作業ではありません。適切な実装には、アニメーションでどのインクリメントを使用するかを適応的に (アニメーションの実行時に) 把握できる効果的な「トゥイーン」アルゴリズムを開発して、スケジュールを守り、可能な限りスムーズにする必要があります。
これを行う最善の方法は、他の人の肩の上に立って、以前に発明されたものを使用することです. 今の時代、これを自分でゼロから書こうとは思わない。CSS3 トランジション/アニメーションで使用するためにありますが、まだどこでもサポートされているわけではありません。jQuery と YUI3 で使用または分析するためにあります。私の最初の選択は、ここで豊富な機能を備えたフレームワークの 1 つを使用することです。フレームワークを他の目的で使用する必要はありません。必要に応じてアニメーションに使用できます。YUI3 では、必要なコードだけを最小限に抑えたライブラリを構築することもできます。jQuery は最初からそれほど大きなものではありません。
いずれかのライブラリを使用することにまだ抵抗がある場合は、ソースを各ライブラリの関連モジュールにダウンロードし、それらがどのように機能するかを調べてください。それぞれでサンプル アプリを作成し、興味深い場所にブレークポイントを設定して、そのしくみを順を追って説明します。これは最良の教師であり、ホスト コンピューターの速度機能に適応できる効果的なトゥイーン アルゴリズムを構築する方法を示します。
ストレート アニメーション (線形イージングを使用) でトゥイーン アルゴリズムがどのように機能するかを理解するために、アニメーションを実行する時間のアニメーション ステップ値を最初に計算します。これはおそらく、システムがサポートできるものに関する推測にすぎません。作成するステップの数をアニメーションの実行時間に分割し、その時間にタイマーを設定して、次のステップをいつ実行するかがわかるようにします。次に、アニメーションの 1 つまたは 2 つのステップを実行すると、実際に経過した時間が表示されます。コンピューターがステップ値に追いつかない場合、予定より遅れることになり、適応してより大きなステップを選択する必要があります。
ここで、線形イージング以外のことをしたい場合は、明らかにさらに複雑になります。
Firefox と Chrome には、スムーズなアニメーションを支援する新しい実験的な API もいくつか実装されています。これは、jQuery ソースが利用可能な場合に使用されるため、jQuery ソースを調べたときに自分で発見しました。Chrome では webkitRequestAnimationFrame と呼ばれ、これについては Firefox ブログ投稿 で読むことができます。
最新のブラウザーをターゲットにしている場合、CSS トランジションを使用すると作業が楽になります (firefox の例、他のブラウザーの場合は -moz プレフィックスを変更します)。
<body>
<input type="button" onclick="move()" value="press" />
<div id="sq" style="position:absolute; top:50px; left:50px; height:50px; width:50px; background-color:Black; -moz-transition : all 0.8s ease 0s;" />
</body>
そして、スクリプト
function move() {
var sq = document.getElementById("sq");
sq.style.left = "300px";
sq.style.top = "150px";
}
最初から書くとしたら、次のようなものから始めます。
function linearEase(start, end, percent) {
return start + ((end - start) * percent);
}
function animateTo(settings) {
var elem = settings.element;
var ease = settings.ease;
var start = { left: elem.offsetLeft, top: elem.offsetTop };
var lastTime = new Date().getTime();
var timeLeft = settings.totalTime;
function update() {
var currentTime = new Date().getTime();
var elapsed = currentTime - lastTime;
timeLeft -= elapsed;
lastTime = currentTime;
var percentDone = 1 - timeLeft/settings.totalTime;
elem.style.top = ease(start.top, settings.top, percentDone) + "px" ;
elem.style.left = ease(start.left, settings.left, percentDone) + "px" ;
if(timeLeft > 0) {
setTimeout(update, 33);
}
}
update();
}
たとえば、次の 2 秒間で div を (50,50) に移動するには、次のようにします。
var elem = document.getElementById("animatable");
setTimeout(function() {
animateTo({
element: elem,
left: 50,
top: 50,
totalTime: 2000,
ease: linearEase
})
}, 10);
これは、この種のことを行うためのかなり標準的なパターンです。要素の位置を取得してスタイルを設定する方が確実に実装できるはずです。しかし、関数を抽象化するease
ことで、長期的にはあなたの人生がずっと楽になります。ここでは単純な線形イージングを提供しましたが、他のより複雑なイージング アルゴリズムも同じインターフェイスに従います。
注意すべきもう 1 つの点は、タイムアウトと間隔が設定された時間に実行されるとは限らないことです。そのため、通常はトランジションの実行に必要な合計時間を設定し、最後のトランジションからの経過時間を把握するのが最善です。あなたがレンダリングした時間。
また、一度に多数の要素をアニメーション化する場合は、これを 1 つの「レンダリング ループ」にリファクタリングします。への呼び出しはanimateTo
ワーカーをワーカーのキューにプッシュしますが、setTimeout
経過時間を計算してから各ワーカーを呼び出すループしか持たないため、無数のtimeout
クロージャーが浮かんでいることはありません。
とにかく、ここでフィドル