質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CSS3

CSS(Cascading Style Sheet)の第3版です。CSS3と略されることが多いです。色やデザインを柔軟に変更することが可能になります。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

3回答

8621閲覧

javascriptでsetIntervalを使うたびに移動速度が上がってしまう

owl

総合スコア42

CSS3

CSS(Cascading Style Sheet)の第3版です。CSS3と略されることが多いです。色やデザインを柔軟に変更することが可能になります。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2017/10/09 16:03

###前提
前回の質問でdivのboxをjavascriptのみでアニメーション移動させることについて質問しましたが、あれから試行錯誤を重ねて成功しました。

現状としましてはクリックした箇所にboxがイージングアニメーションをしながら移動します。

###発生している問題
一つだけ問題なのが、最初にクリックした時のboxの移動速度と10回ほどクリックした時の移動速度が変わってしまうことです。
クリックしてboxを移動させる度に移動速度が速くなってしまいます。
setIntervalの使い方が間違っているのか、それとも原因が他にあるのか手詰まり状態です。

ご回答どうぞよろしくお願いします。
該当のソースコードをjsfiddleにアップしていますので、ご活用ください。
https://jsfiddle.net/ululami/c29aLprv/

###該当のソースコード

javascript

1var box = document.getElementById('box'); 2var clientRect; 3//boxのx軸とy軸 4var boxX; 5var boxY; 6//クリックした箇所のx軸とy軸 7var clickX = 0; 8var clickY = 0; 9 10document.addEventListener('click', function(event){ 11 clientRect = box.getBoundingClientRect(); 12 13 boxX = clientRect.left; 14 boxY = clientRect.top; 15 16 clickX = event.clientX; 17 clickY = event.clientY; 18 19 setInterval(function(){ 20 box.style.left = boxX + 'px'; 21 box.style.top = boxY + 'px'; 22 23 if(boxX < clickX || boxY < clickY){ 24 boxX = boxX + (clickX - boxX) / 50; 25 boxY = boxY + (clickY - boxY) / 50; 26 } else if(boxX  > clickX || boxY > clickY){ 27 boxX = boxX - (boxX - clickX) / 50; 28 boxY = boxY - (boxY - clickY) / 50; 29 } 30 }, 30) 31});

html

1<div id="box"></div>

css

1*{ 2 margin: 0; 3 padding: 0; 4} 5 6#box{ 7 width: 50px; 8 height: 50px; 9 background: red; 10 position: relative; 11}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

どんどん速くなるのはedo_m18さんのおっしゃるとおり、setIntervalを何回も実行しているからですね。止めるには、setIntervalが返すinterval IDを変数に保存しておき、止めたい時にclearIntervalにそのIDを渡します。

lang

1var intervalID = setInterval( ... ); 2 3// stop the interval 4clearInterval(intervalID);

以下は気になった点です。

次のboxの座標を次のように計算していますが、

lang

1 if(boxX < clickX || boxY < clickY){ 2 boxX = boxX + (clickX - boxX) / 50; 3 boxY = boxY + (clickY - boxY) / 50; 4 } else if(boxX  > clickX || boxY > clickY){ 5 boxX = boxX - (boxX - clickX) / 50; 6 boxY = boxY - (boxY - clickY) / 50; 7 }

どちらの場合も同じ結果になるので、場合分けする必要はないと思います。

lang

1 2 boxX = boxX + (clickX - boxX) / 50; 3 boxY = boxY + (clickY - boxY) / 50; 4

質問の趣旨から外れてしまいますが、setIntervalではなくwindow.requestAnimationFrame()を使うと滑らかなアニメーションができます。

DEMO

lang

1var box = document.getElementById('box'); 2var clientRect = box.getBoundingClientRect(); 3var boxX = clientRect.left; 4var boxY = clientRect.top; 5 6var clickX = 0; 7var clickY = 0; 8 9document.addEventListener('click', function(event){ 10 clickX = event.clientX; 11 clickY = event.clientY; 12}); 13 14window.requestAnimationFrame(step); 15 16var lastTime; 17 18function step(timestamp) { 19 if (!lastTime) lastTime = timestamp; 20 var deltaTime = timestamp - lastTime; // 前フレームからの経過時間 21 move(deltaTime); 22 window.requestAnimationFrame(step); 23 lastTime = timestamp; 24} 25 26function move(delta) { 27 boxX += (clickX - boxX) / 200 * delta; 28 boxY += (clickY - boxY) / 200 * delta; 29 box.style.left = boxX + 'px'; 30 box.style.top = boxY + 'px'; 31}

投稿2017/10/09 17:17

karamarimo

総合スコア2551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

owl

2017/12/22 07:13

返信遅れて申し訳ありません。 requestAnimationFrameを使うことを考えていなかったので、 これを使用したらスムーズにアニメーションし、大変満足しています。 本当にありがとうございます。
guest

0

多分、クリックするたびにsetIntervalで呼ばれる関数が重複して呼ばれるからじゃないかと思います。

クリックごとに前のsetIntervalを止めるなどして処理が重複しないようにしたら速度が変化することがなくなると思います。

投稿2017/10/09 16:10

edo_m18

総合スコア2283

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

owl

2017/12/22 07:12

返信遅れて申し訳ありません。 まさにsetIntervalの部分クリックするたびに重複していることが原因でした。 大変勉強になりました。 本当にありがとうございます。
guest

0

ベストアンサー

setTimeoutを使うという手もあるでしょう。目的地にたどり着いていなければ再帰的に呼び出すという方法です。

が、たどり着いているかを判断する上で、もっと重大な問題が存在しています。

結論としては今回のプログラムとは全く関係無いのですが、わかりやすい例として、
アキレスと亀のパラドックスをご存知でしょうか?

詳しくはここでは述べませんが、アキレスがいくら速くても、微小時間で見ていくとアキレスは移動する亀には追いつけないというものです。

実は質問者様のプログラムは似たような状況になっているんです。
「残りの距離の1/2だけ進む」というのは良いアイデアだったと思いますが、
これは目的地には極限を取ると着きますが、実際には限りなく近づくだけでたどり着けないんです。

これはconsole.log("boxX : "+boxX+" clickX : "+clickX);のようなコードで確認していただけると思います。

ですから人の目では到着しているように見えても簡単な記述では止めることができません。setTimeoutに変えるだけでも確かに処理は重ならなくなるはずですが、(ほぼ)到着しても処理は止まりません。これは意図した動作では無いはずです。

ですからMath.round()等の関数を使用して区切りのいい所で止まるようにしましょう。

以下コードです。1つめは大体の位置が同じなら何もせず、違っていれば再帰処理させるというものです。(1つめの方はkaramarimo様の回答を参考に場合分けは消しました。)

javascript

1var box = document.getElementById('box'); 2var clientRect; 3//boxのx軸とy軸 4var boxX; 5var boxY; 6//クリックした箇所のx軸とy軸 7var clickX = 0; 8var clickY = 0; 9// 終了判定用 10var preX = 0; 11var preY = 0; 12 13document.addEventListener('click', function(event){ 14 clientRect = box.getBoundingClientRect(); 15 16 boxX = clientRect.left; 17 boxY = clientRect.top; 18 19 clickX = event.clientX; 20 clickY = event.clientY; 21 22 var move = function(){ 23 box.style.left = boxX + 'px'; 24 box.style.top = boxY + 'px'; 25 26 preX = Math.round(boxX*100); 27 preY = Math.round(boxY*100); 28 29 boxX += (clickX - boxX) / 50; 30 boxY += (clickY - boxY) / 50; 31 32 // 小数第3位を四捨五入して小数第2位で比較 33 if(Math.round(boxX*100)!=preX || Math.round(boxY*100)!=preY) setTimeout(move,30); 34 //console.log("boxX : "+boxX+" clickX : "+clickX); 35 //console.log("boxY : "+boxY+" clickY : "+clickY); 36 }; 37 setTimeout(move,30); 38});

jsfiddle

または比較部分で丸めるのもありです。

javascript

1// 省略 2 if(Math.round(boxX*10) < clickX*10 || Math.round(boxY*10) < clickY*10){ 3 boxX = boxX + (clickX - boxX) / 50; 4 boxY = boxY + (clickY - boxY) / 50; 5 setTimeout(move,30); 6 } else if(Math.round(boxX*10) > clickX*10 || Math.round(boxY*10) > clickY*10){ 7 boxX = boxX - (boxX - clickX) / 50; 8 boxY = boxY - (boxY - clickY) / 50; 9 setTimeout(move,30); 10 } 11 //console.log("boxX : "+boxX+" clickX : "+clickX); 12 //console.log("boxY : "+boxY+" clickY : "+clickY); 13 }; 14 setTimeout(move,30); 15// 省略

(長文失礼しました。m(_ _)m)

投稿2017/10/09 17:57

編集2017/10/09 18:06
namnium1125

総合スコア2043

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

owl

2017/12/22 07:11

返信遅れて申し訳ありません。 とても詳しく回答していただき大変勉強になりました。 特に到達地点に限りなく近づくかゴールに到達できない部分が大変納得しました。 本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問