スクロールと連動してメニューを動かす(過去のリメーク版)

ちょっと手直し。オフセットと加速度の変更が可能。
常にタイマーが効いていたのを変更

<!DOCTYPE html>
<title>はじっこにいすわる4</title>

<style type="text/css"> 
#TOP { height:3000px; }

</style>

<div id="TOP">
  <p>スクロールすると、右端にメニューが追いかけてくる。
  <p>スクロールが必要ない場合は、消える
</div>

<div id="menu1">
  <a href="#TOP">Top</a>
</div>
<div id="menu2">
  <a href="#TOP">Top</a>
</div>

<script type="text/javascript">

(function () { //@cc_on

  function Elevator (arg) {
    this.view     = arg.view;      // window
    this.body     = arg.body;      // document.documentElement or body
    this.node     = arg.node;      // target node
    this.accell   = arg.accell;    // acceleration (1 < accell)
    this.interval = arg.interval;  // timer interval
    this.offset   = arg.offset;    // target offset position 
    this.timerId  = null;          // timer
  }
  
//______________________________________________________________________

  function Decorator (alpha) {
    if (alpha < 0)
      return this.visibility = 'hidden';
    
    if (100 < alpha)
      alpha = 100;
    
    this.visibility = 'visible';
     
     /*@if (@_jscript)
    this.filter = 'Alpha(opacity=' + alpha + ')'; @else@*/
    this.opacity = String (alpha / 100); /*@end@*/
  }


  function Locator (x, y) {
    this.top = y + 'px';
    this.left = x + 'px';
  }
  

  function Elevator_start () {
    if (! this.timerId) {
      var that = this;
      var cbFunc = function () { Elevator_onTimer.call (that) };
      this.timerId = this.view.setInterval (cbFunc, this.interval);
    }
  };


  function Elevator_stop () {
    if (this.timerId) {
      this.view.clearInterval (this.timerId);
      this.timerId = null;
      Decorator.call (this.style, -1);
    }
  };


  function Elevator_onTimer () {
    var e = this.node;
    var b = this.body;
    var v = this.view;
    var s = e.style;
    var a = this.accell;
    var o = this.offset;
    
    var offsetX = b.clientWidth - e.offsetWidth - o.x;
    var offsetY = b.clientHeight -e.offsetHeight - o.y;

    var pointerX = /*@if (@_jscript) b.scrollLeft @else@*/ v.pageXOffset /*@end@*/ + offsetX;
    var pointerY = /*@if (@_jscript) b.scrollTop  @else@*/ v.pageYOffset /*@end@*/ + offsetY;
    
    var diffX = pointerX - e.offsetLeft;
    var diffY = pointerY - e.offsetTop;
    
    if (0 === diffX)
      if (0=== diffY)
        Elevator_stop.call (this);

    var x = e.offsetLeft + Math.floor (diffX / a + (0 < diffX));
    var y = e.offsetTop + Math.floor (diffY / a + (0 < diffY));

    Decorator.call (s, y - offsetY);
    Locator.call (s, x, y);
  };


  function Elevator_init (target, accell, interval, offset) {
    if (1 > arguments.length)
      return null;
    
    var doc = target.ownerDocument;
    var view = doc./*@if (@_jscript) parentWindow @else@*/ defaultView /*@end@*/;
    var style = target.style;
    var arg = {
      view     : doc./*@if (@_jscript) parentWindow @else@*/ defaultView /*@end@*/,
      body     : doc[(doc.compatMode == 'CSS1Compat') ? 'documentElement' : 'body'],
      node     : target,
      accell   : accell || 2,
      interval : interval || 50,
      offset   : offset || { x: 20, y: 50 }
    };
    var elevator = new Elevator (arg);
    
    function onScroll (evt) {
      Elevator_start.call (elevator);
    }

    function onUnload (evt) {
      doc./*@if (@_jscript) detachEvent ('on' + @else@*/ removeEventListener ( /*@end@*/ 'scroll', onScroll, false);
      view./*@if (@_jscript) detachEvent ('on' + @else@*/ removeEventListener ( /*@end@*/ 'unload', arguments.callee, false);
      
      view = doc =
        style = arg = elevator
        onScroll = onUnload =
          null;
    }

    doc./*@if (@_jscript) attachEvent ('on' + @else@*/ addEventListener (/*@end@*/ 'scroll', onScroll, false);
    view./*@if (@_jscript) attachEvent ('on' + @else@*/ addEventListener (/*@end@*/ 'unload', onUnload, false);

    style.position = 'absolute';
    elevator.start ();

    return elevator;
  }


//______________________________________________________________________

  Elevator.init = Elevator_init;
  
  Elevator.prototype.start   = Elevator_start;
  Elevator.prototype.stop    = Elevator_stop;
  
  this.Elevator = Elevator;
  
})();


Elevator.init (document.getElementById ('menu1'));
Elevator.init (document.getElementById ('menu2'), 10, 30, { x: 100, y: 50});
</script>