みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

JQueryのイーズインとイーズアウト

http://d.hatena.ne.jp/KAZUMiX/20080418/scrollsmoothly#c

上記のscrollsmoothly.jsを、いじっておりまして
製作者様のサイトでも質問をしてみたのですが、結局どうすればいいのか
いろいろ調べた中でもよくわかりませんでしたので
ご教授いただければ幸甚です。

scrollsmoothly.jsでは、イーズアウトをいうアニメーションをつかっているようで
スタートはすっと動き、最後がゆっくり着地するというアニメーションとなっているようです。

この逆に最初がゆっくりはじまるのがイーズインというものですが
両方を一緒に上記のscrollsmoothly.jsの中でつかいたいのですが

どこにどのようなコードを書けばいいのかわかりません。

製作者様には
---------------------------
で、このスクリプトはイーズアウトのことしか考えていないので、両方組み合わせるとなると少し面倒です。単純に両方を組み合わせるとなると、目標座標の半分まではイーズイン、半分から最後まではイーズアウトという風になります。
この辺、柔軟に対応するための方法や式などは「イージング」で調べるとといろいろありますので、がんばって改造してみて下さい。
---------------------------

といわれ、いろいろ調べてみたのですが結局、どこをどうさわればいいのか
具体的なことがわからず、試してみたのですが、動かないのです・・・。

どなたご教授くださいませ・・・・。

投稿日時 - 2010-12-29 12:54:00

QNo.6413911

すぐに回答ほしいです

質問者が選んだベストアンサー

【その後】
このロジックで、かなり強引に、「始めちょろちょろ中ぱっぱ終わりちょろちょろ」になるようなイージングが動作するようになったけど、この辺が限界か、大幅に書き換えた方がよいかも。
(変更した関数)
   function setScroll(hash){
    // ハッシュからターゲット要素の座標をゲットする
    var targetEle = d.getElementById(hash.substr(1));
    if(!targetEle)return;
    //alert(scrollSize.height);
    // スクロール先座標をセットする
    var ele = targetEle;
    var x = 0;
    var y = 0;
    while(ele){
     x += ele.offsetLeft;
     y += ele.offsetTop;
     ele = ele.offsetParent;
    }
    var maxScroll = getScrollMaxXY();
    targetX = Math.min(x, maxScroll.x);
    targetY = Math.min(y, maxScroll.y);
    targetHash = hash;
//ここに挿入
    x = d.documentElement.scrollLeft||d.body.scrollLeft;
    y = d.documentElement.scrollTop||d.body.scrollTop;
    if((targetX - x) >= 0)
    centerX = Math.floor((targetX - x) / 2) + x;
    else centerX = (Math.floor((targetX - x) / 2) + x) * -1;
    if((targetY - y) >= 0)
    centerY = Math.floor((targetY - y) / 2) + y;
    else centerY = (Math.floor((targetY - y) / 2) + y) * -1;
//ここまで
    // スクロール停止中ならスクロール開始
    if(!scrolling){
     scrolling = true;
     scroll();
    }
   }

   function scroll(){
    var currentX = d.documentElement.scrollLeft||d.body.scrollLeft;
    var currentY = d.documentElement.scrollTop||d.body.scrollTop;
//ここから書き換え
    if(centerX >=0){
    if(currentX >= centerX)
      var vx = (targetX - currentX) * easing;
     else var vx = currentX * easing + 1;
    }else{
    if(currentX < Math.abs(centerX))
      var vx = (targetX - currentX) * easing;
     else var vx = (2 * centerX + currentX) * easing - 1;
    }
    if(centerY >=0){
    if(currentY >= centerY)
     var vy = (targetY - currentY) * easing;
     else var vy = currentY * easing + 1;
    }else{
    if(currentY < Math.abs(centerY))
     var vy = (targetY - currentY) * easing;
     else var vy = (2 * centerY + currentY) * easing - 1;
    }
    //console.log(targetY+":"+centerY+":"+currentY+":"+vy);
//ここまで
    var nextX = currentX + vx;
    var nextY = currentY + vy;
 -------
以下変更なし。

投稿日時 - 2011-01-12 11:41:54

補足

本当にありがとうございます!!
見捨てられたかと思い、めちゃくちゃ困っていました・・・。

教えていただいた形でさせていただきますと、はじめゆっくり、中ぱっぱ
おわりもゆっくりといった動きをするのですが、斜めに動くときにまっすぐに斜めに動かず、一度、横に動いてからあがる(下がる)といった動きになります・・・。

なぜでしょうか・・・?
回答No.04の方のものも一度試してみます☆

投稿日時 - 2011-01-14 11:21:01

お礼

回答No04の方の動きも試させていただきました。

狙っていた動きではありませんが、
逆にこっちの方が、かっこいいですね☆

うまく表現ができないのですが、

Section5からSection3に移動する際、
Section6に一度、移動しながらなめらかにSection3に上っていくような動きをします。

逆に、Section3からSection5に戻る際は
Section1を通って動きます。


真横もしくは真下(Section3から1というように)に動くときは
狙った動きどうりに動きますし、ジャンプ移動中に別のリンクをクリックしても
ちゃんと移動先がなめらかに切り替わります。

他の質問も含め、年末年始と、かなり助かりました!!
本当にありがとうございます☆
いろいろと試してみてまたわからないことがでてくるかと思いますので
その際はご質問させていただきます☆

もし可能であれば回答No.04の方で補足させていただいている
質問も教えていただけると助かります☆

投稿日時 - 2011-01-14 11:21:17

ANo.3

このQ&Aは役に立ちましたか?

3人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.5

#4です。

>1)移動中はリンクをクリックできないようにする
クリックしてもをキャンセルするという意味ですよね?
そのあたりはオリジナルのままなのでキャンセルされるはず… と思って見直してみたら、クリックされたら以降の処理に関係なくtargetの座標を書換えちゃってくれるようになってますねぇ。

動作中だったら setScrollを実行する必要はないので、setScroll()の最初に
 if (scrolling) return;
を追加すればご質問のようになります。(そのほうが無駄な処理もなくなるし)



>2)移動中にリンクをクリックした際は、そちらへ移動するようにかわる
こちらの仕様のほうがリーズナブルかもしれませんね。
クリックされたら、スクロール中の処理を中断して新しいスクロールを始めるようにすれば良いのですが、オリジナルの骨格を利用しているので、修正箇所が分散します。

ついでに、移動速度が速いほうが良いらしいので(#3の補足を見て)、easingFuncも書換えてみました。(係数変えただけですけど)
(早いブラウザだとあまり効果が感じられなくなってしまいましたが…)
#4にも書いたように、この部分の関数を帰ることで動きの種類を変えることが可能になっています。⊿pを返す形式にしてしまったのでバウンスなどはできませんが、intervalや必要時間を変えられるようにして、タイマーと変化量の関係の関数にすれば、バウンドさせたりとかいろいろな移動形式を可能にできます。

(1)最初のほうの
 var scrolling = false; → var scrolling = null;

(2) setScrollの終わりのほうの4行
 if(!scrolling){
  scrolling = true;
  scroll();
 }
の部分を
  scroll();
の1行に置換え

(3) 入替えたscroll()部分を以下に再度入替え
function scroll(){
 if (scrolling) clearInterval(scrolling); //追加
 var startX = d.documentElement.scrollLeft||d.body.scrollLeft;
 var startY = d.documentElement.scrollTop||d.body.scrollTop;
 var deltaX = targetX - startX;
 var deltaY = targetY - startY;
 var progress = 0;
 var limit = 0.9995;

 scrolling = setInterval(function(){ //修正
  progress += easingFunc(progress);
  var x = startX + progress * deltaX;
  var y = startY + progress * deltaY;
  if(progress > limit) {
   scrollTo(targetX, targetY); //終了処理部分を書換え
   location.hash = targetHash;
   clearInterval(scrolling);
   scrolling = null;
  }else{
   scrollTo(parseInt(x), parseInt(y));
}
}, interval);
}

function easingFunc(p) {
// Sample4
var a = 1/3, r = p<0.5?p:(1-p);
return Math.max(r * a, 0.008);
}

(1)~(3)の修正をすればご質問のようになりますが、速度を速くしたので移動中に正しくクリックするのが難しそう。
(動作確認は速度を遅くしてやりました)

投稿日時 - 2011-01-20 19:22:19

ANo.4

No1様がすでにご指摘の部分を調整すれば良いみたいですが・・・

ちょっと効率は悪いですが、function scroll()部分の差替えの形にしてみました。
(あちこち変えると面倒なので、一箇所にまとめた…ので効率が悪い?)
easingFunc()は進捗率p(=0~1)に対して、増加分⊿pを返す関数にしています。
この関数を書換える事で、動作を変えられるようになっています。

Sample1は等速運動、Sample2は三角関数で、Sample3はオリジナルに近い差分に対する比で増加分を決めています。
係数などを調整すれば、移動速度や変化の率などを変えられます。
(増加分を返す関数にしてしまったので、行きつ戻りつみたいなのはやりにくいですが…)

* オリジナルサイトのサンプルで試す場合、HTMLのリンク先が絶対参照になっているため修正しないとオリジナルサイトへ遷移してしまい、スクリプトの変更がキャンセルされてしまいますのでご注意。(#2様が効果がわからないと書いておられるのはこのせいかも)


//(全角空白は半角に)
function scroll(){
 var startX = d.documentElement.scrollLeft||d.body.scrollLeft;
 var startY = d.documentElement.scrollTop||d.body.scrollTop;
 var deltaX = targetX - startX;
 var deltaY = targetY - startY;
 var progress = 0;
 var limit = 0.9995;

 var timerId = setInterval(function() {
  progress += easingFunc(progress);
  var x = startX + progress * deltaX;
  var y = startY + progress * deltaY;
  if(progress > limit) {
   // 目標座標付近に到達していたら終了
   scrollTo(targetX, targetY);
   scrolling = false;
   location.hash = targetHash;
   clearInterval(timerId);
   timerId = null;
  }else{
   // 繰り返し
   scrollTo(parseInt(x), parseInt(y));
  }
 }, interval);
}

function easingFunc(p) {
// Sample1 easingなし(等速)
 //return 0.05;

// Sample2 sin曲線(増加率:a*cos)
 //var a = 0.08, toRad = Math.PI * 0.999; //(p=0の時に0を回避のため)
 //return Math.cos((p-0.5) * toRad) * a;

// Sample3 漸近線(残差/a)
 var a = 1/6, r = p<0.5?p:(1-p);
 return Math.min(Math.max(r * a, 0.001), 0.1);
}

投稿日時 - 2011-01-12 19:09:51

補足

回答ありがとうございます!!大変助かりました。
イメージに近い動きになりました!

以前の質問(yyr446さんに回答いただいた別の質問)で
ロード後、#section9から#section5まで移動するということを
教えていただき、そのように動かしているのですが
そのままにしておくと、setcion1でロードし、section9まで飛んでいってしまいました。


// ドキュメント読み込み完了時の処理
function init(){
// ページ内リンクにイベントを設定する
setOnClickHandler();
// 外部からページ内リンク付きで呼び出された場合
if(incomingHash){
if(window.attachEvent && !window.opera){
// IEの場合はちょっと待ってからスクロール
setTimeout(function(){scrollTo(0,0);setScroll('#'+incomingHash);},200);
}else{
// IE以外はそのままGO
scrollTo(0, 0);
setScroll('#'+incomingHash);
}
}

  //ここから
setScroll("#section5"); //←※01
setTimeout(function(){setScroll("#section5");},1000); //1秒後に移動
  //ここまで
}

// イベントを追加する関数

※01のsection名がもともとは9だったのですが5にかえると、キレイに動きましたので
ここはクリアできました☆

ただ、ひとつ問題がございまして、
ジャンプ中(移動中)に別のリンクを押しても移動が途中で切り替わらず

最後に、パッとリンク先に切り替わってしまいます。

例えば、

1)移動中はリンクをクリックできないようにする
2)移動中にリンクをクリックした際は、そちらへ移動するようにかわる

方法にできますでしょうか?

質問に質問を繰り返し、申し訳ございませんが
ご教授いただければ幸甚です。

投稿日時 - 2011-01-14 11:11:25

ANo.2

年末年始とほったらかしにしてすまんこってす。

変更箇所は、
   function setScroll(hash){
    // ハッシュからターゲット要素の座標をゲットする
    var targetEle = d.getElementById(hash.substr(1));
    if(!targetEle)return;
    //alert(scrollSize.height);
    // スクロール先座標をセットする
    var ele = targetEle;
    var x = 0;
    var y = 0;
    while(ele){
     x += ele.offsetLeft;
     y += ele.offsetTop;
     ele = ele.offsetParent;
    }
    var maxScroll = getScrollMaxXY();
    targetX = Math.min(x, maxScroll.x);
    targetY = Math.min(y, maxScroll.y);
    targetHash = hash;
//ここに挿入
    x = d.documentElement.scrollLeft||d.body.scrollLeft;
    y = d.documentElement.scrollTop||d.body.scrollTop;
    centerX = Math.floor((targetX - x) / 2);
    centerY = Math.floor((targetY - y) / 2);
//ここまで
    // スクロール停止中ならスクロール開始
    if(!scrolling){
     scrolling = true;
     scroll();
    }
   }

   function scroll(){
    var currentX = d.documentElement.scrollLeft||d.body.scrollLeft;
    var currentY = d.documentElement.scrollTop||d.body.scrollTop;
//ここから書き換え
    //var vx = (targetX - currentX) * easing;
    //var vy = (targetY - currentY) * easing;

    if(currentX >= centerX) var vx = (targetX - currentX) * easing;
    else var vx = (targetX - currentX) / easing;
    if(currentY >= centerY) var vy = (targetY - currentY) * easing;
    else var vy = (targetY - currentY) / easing;
//ここまで
    var nextX = currentX + vx;
    var nextY = currentY + vy;
    if((Math.abs(vx) < 1 && Math.abs(vy) < 1)
     || (prevX === currentX && prevY === currentY)){
     // 目標座標付近に到達していたら終了
     scrollTo(targetX, targetY);
     scrolling = false;
     //location.hash = targetHash;
     prevX = prevY = null;
     return;
    }else{
     // 繰り返し
     scrollTo(parseInt(nextX), parseInt(nextY));
     prevX = currentX;
     prevY = currentY;
     setTimeout(function(){scroll()},interval);
    }
   }

なんです。これで動作はするんですが、イーズインとイーズアウト が効いているのかどうか速すぎてよくわからんとゆうか、intervalミリ秒数増やしてみても、やっぱり効いて無いような気がします。しきりなおしですね。ぺこり

投稿日時 - 2011-01-11 17:13:05

お礼

上記のお礼内を訂正します・・・。


--------------------------
回答No04の方の動きも試させていただきました。

狙っていた動きではありませんが、
逆にこっちの方が、かっこいいですね☆

うまく表現ができないのですが、

--------------------------

ここの部分ですが、こっちの動きというのは
yyr446さんの動きのことです。

すいません、読み直していて
誤解を与えそうなので注釈しておきます☆

投稿日時 - 2011-01-15 15:33:21

ANo.1

引き続き前の回答者です。
イーズインしてイーズアウトで終るようにしたいんですね、製作者様がヒントをくれてます。
 先頭の方にある
  var easing = 0.25;
 これが、イージング率ですね。
改造するところは、function scroll(){}の中です。
  var vx = (targetX - currentX) * easing;
  var vy = (targetY - currentY) * easing;
  var nextX = currentX + vx;
  var nextY = currentY + vy;
で、終わりに近づくにつれ、移動量 vx,vy が 小さくなっていってますね。
これを前半は真ん中に近づくまでは移動量 vx,vy が大きくなるようにし、
後半は小さくなるようにすればよいかと。

※最初に真ん中の位置centerX,centerYを先頭で定義します。
そして、function setScroll(){}で計算してセットします。
targetHash = hash;の下あたりで、
  x = d.documentElement.scrollLeft||d.body.scrollLeft;
  y = d.documentElement.scrollTop||d.body.scrollTop;
  centerX = Math.floor((targetX - x) / 2);
  centerY = Math.floor((targety - y) / 2);
としてから、
  if(!scrolling){
  scrolling = true;
  scroll();
  }

そして、function scroll(){}の中で

 if(currentX >= centerX) var vx = (targetX - currentX) * easing;
  else var vx = (targetX - currentX) / easing;
 if(currentY >= centerY) var vy = (targetY - currentY) * easing;
  else var vy = (targetY - currentY) / easing;

とする。
うーん、安直すぎてだめかも...
いろいろお試しあれ!

投稿日時 - 2010-12-29 15:56:32

補足

なんどもご回答ありがとうございます☆
ご教授いただいたのですが、動きませんでした・・・。
なにがわるかったのでしょうか?

--------------------------

function scroll(){
var currentX = d.documentElement.scrollLeft||d.body.scrollLeft;
var currentY = d.documentElement.scrollTop||d.body.scrollTop;
var vx = (targetX - currentX) * easing;
var vy = (targetY - currentY) * easing;
var nextX = currentX + vx;
var nextY = currentY + vy;
if((Math.abs(vx) < 1 && Math.abs(vy) < 1)
|| (prevX === currentX && prevY === currentY)){
// 目標座標付近に到達していたら終了
scrollTo(targetX, targetY);
scrolling = false;
//location.hash = targetHash; ← ここは、コメントアウトしたままです。

   //ここから

   x = d.documentElement.scrollLeft||d.body.scrollLeft;
   y = d.documentElement.scrollTop||d.body.scrollTop;
  centerX = Math.floor((targetX - x) / 2);
  centerY = Math.floor((targety - y) / 2);

if(!scrolling){
  scrolling = true;
  scroll();
  }
    
   if(currentX >= centerX) var vx = (targetX - currentX) * easing;
   else var vx = (targetX - currentX) / easing;
   if(currentY >= centerY) var vy = (targetY - currentY) * easing;
    else var vy = (targetY - currentY) / easing;

    //ここまで挿入しました。

prevX = prevY = null;
return;
}else{
// 繰り返し
scrollTo(parseInt(nextX), parseInt(nextY));
prevX = currentX;
prevY = currentY;
setTimeout(function(){scroll()},interval);
}
}

--------------------------


単純に、コピペしただけなのですが、最後のif(currentX >= centerX) var vx = (targetX - currentX) * easing;~あたりを
どこにいれればいいかがよくわかりません・・・。

ここをいれなければ、動いているのですが(目的の動きではないです。)if(currentX >= centerX) var vx = (targetX - currentX) * easing;~を
いれると、まったく動かなくなってしまいます。

function scroll(){のあとの、var vx あたりを消して、差換えてみたのですが
やはり動きませんでした・・・。

年末のお忙しいときに申し訳ございませんが何卒ご教授くださいませ・・・。

投稿日時 - 2010-12-30 16:46:04

お礼

なんども申し訳ございません・・・。
あれから色々と見直してみますと、せっかく教えていただいている部分を読み間違えている箇所がございました・・・。

教えていただいた「function setScroll」の「targetHash = hash;」の下あたりに挿入するあたりを上で勘違いしておりました。
しかし、やはり動きません・・・。

教えていただいた部分で2箇所わからないことがございます。

■1) まず、centerX,Yをどこで定義すればよいのでしょうか?
------------------------------------
(function(){
var easing = 0.20;
var interval = 100; //スピード

ここに、

  var centerX= 0;
var centerY = 0;
------------------------------------
を追記すればよいのでしょうか?
初歩的な質問で申し訳ございません・・・。


■2) 次に、「function scroll(){}の中に挿入する

------------------------------------

 if(currentX >= centerX) var vx = (targetX - currentX) * easing;
  else var vx = (targetX - currentX) / easing;
 if(currentY >= centerY) var vy = (targetY - currentY) * easing;
  else var vy = (targetY - currentY) / easing;

------------------------------------

これは、function scroll(){のどこに挿入すればよいのでしょうか?



現在、

function scroll(){
var currentX = d.documentElement.scrollLeft||d.body.scrollLeft;
var currentY = d.documentElement.scrollTop||d.body.scrollTop;
var vx = (targetX - currentX) * easing;
var vy = (targetY - currentY) * easing;
var nextX = currentX + vx;
var nextY = currentY + vy;
if((Math.abs(vx) < 1 && Math.abs(vy) < 1)
|| (prevX === currentX && prevY === currentY)){
// 目標座標付近に到達していたら終了
scrollTo(targetX, targetY);
scrolling = false;
//location.hash = targetHash; //コメントアウトをはずすとアンカーがでる。
prevX = prevY = null;
return;
}else{
// 繰り返し
scrollTo(parseInt(nextX), parseInt(nextY));
prevX = currentX;
prevY = currentY;
setTimeout(function(){scroll()},interval);
}


となっており、
var currentX = d.documentElement.scrollLeft||d.body.scrollLeft;
var currentY = d.documentElement.scrollTop||d.body.scrollTop;
var vx = (targetX - currentX) * easing;
var vy = (targetY - currentY) * easing;

ここを削除して、差し替える方がよいのでしょうか?

色々試してみてはいるのですが、基礎的な部分がないため、わからないところがわからないような状態です・・・。
どうかご教授いただければ幸甚です。

投稿日時 - 2011-01-01 17:53:02

あなたにオススメの質問