動き自体はできたのですが、早くスクロールすると回転が途中で止まってしまう
【考察と原因】
1.ブラウザでonscrollイベントが発火する間隔はそれほど頻繁ではないため、
スクロールバーを動かす速度が速くなると、
onScroll内における$(this).scrollTop() の値の間隔が大きくなっています。
[onScroll()内における、$(this).scrollTop() の値の変化]
0~100の範囲で動かすとする。
ゆっくり動かした場合:0 -> 1 -> 2 -> 3 -> 4 ... 99 -> 100 (間隔が狭い)
速く動かした場合 :0 -> 5 -> 10 -> 15 -> 20 ... 95 -> 100 (間隔が広い)
2.スクロールバーがスクロールエリアの上端もしくは下端に到達すると、そこでonScrollイベントは発火しなくなります。
3.上端または下端に到達してonscrollが発火しなくなったタイミングの、onScroll()におけるscrollTop()の値は、必ずしも、上端または下端にスクロールバーを位置させたときのscrollTop()の値を指しているとは限りません。
たいていの場合、上端/下端で止める直前に取得されたscrollTop() の値になっています。
(上記の例で言えば、ゆっくり動かせば「99」で止まるが、速く動かすと「95」で止まる)
これが、「回転が途中で止まってしまう」ように見える原因の一つです。
【対策】
onscrollイベントが発火しなくなった後、一定時間後に同じ処理を呼び出して、スクロールが止まった時点のscrollTop()の値を反映するようにすればよいでしょう。
下記のコードの
clearTimeout( id );
id = setTimeout( onEnded, INTERVAL );
の部分になります。
ここでは、onscrollがINTERVAL未満の間隔で発火中は、発火の度にclearTimeoutが呼ばれ、onEndedは実行されません。
スクロールが止まると、clearTimeoutが呼ばれないので、INTERVALミリ秒後に onEndedが実行されることになります。
スクロールが止まった場合は、止まった場所のscrollTopで補正をかけたいので、isScrollingというフラグを使用して条件分岐するようにしています。
【その他】
・transformを実行するときの基準(windowB - (elem1 * 2 - winH))が0から90の間に限定されていますが、これだと、条件によって範囲を逸脱するとき(0を下回るとき/90を上回るとき)回転が止まったように見えます。
したがって、ここでも場合分けして、適切な値を設定した上でtransformをかける必要があると思います。
・スクロール中にrotateYの引数が90degになるとスクロールがリセットされてしまうので、計算結果が90になる場合はほんの少しだけ値をずらしています。
・transitionを使うことで、スクロール中の回転及び、上端・下端に到達したときの直近の形状からの変化を滑らかに見せています。
js
1 const $logo = $(".logo");
2 let id = null;
3 const INTERVAL = 100;
4
5 function onEnded() {
6 doTransform(0.3, false)
7 id = null;
8 };
9
10 /*
11 duration: transitionの実行時間
12 isScrolling: スクロール中かどうか
13 */
14 function doTransform(duration, isScrolling){
15 const winH = $(window).height();
16 const elem1 = $logo.offset().top;
17 const windowB = $(this).scrollTop();
18 if (!isScrolling || (windowB > elem1 * 2 - winH)) {
19 let a = windowB - (elem1 * 2 - winH);
20 if (a == 45) {
21 a = 45.5;
22 } else if (a < 0) {
23 a = 0;
24 } else if (a > 90) {
25 a = 90;
26 }
27 $logo.css({
28 transform: "rotateY(" + a * 2 + "deg)",
29 transition: duration+"s"
30 });
31 }
32 }
33
34 function onScroll() {
35 clearTimeout(id);
36 id = setTimeout( onEnded, INTERVAL );
37 doTransform(0.1, true)
38 }
39 window.onscroll = onScroll;
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/07/29 11:26