JavaScript製のスクロールバーを作った その2

※ライブラリ化しました
http://storehouse.sakura.ne.jp/scrollbar.html
ついでにホイールにも対応してみた。
Operaで動くかは不明。一応、動くようにした。

<html>
  <head>
    <script type="text/javascript" src="prototype.js"></script>
    <script type="text/javascript">
ScrollBar = Class.create();
ScrollBar.prototype = {
  initialize: function(element) {
    this.bar = $(element);
    this.bar.height = parseInt(Element.getStyle(this.bar, 'height'));
    this.knob = this.bar.getElementsByTagName('div')[0];
    this.knob.height = parseInt(Element.getStyle(this.knob, 'height'));
    this.wheel_increment = 5;
    this._move = null;

    Event.observe(this.knob, 'mousedown', function(event) {
      Event.stop(event)
      var top = this.position();
      var start_y = Event.pointerY(event);

      this._move = function(move_event) {
        var offset_y = Event.pointerY(move_event) - start_y;
        if (this.snap && (offset_y % this.snap) != 0) { return; }
        var moved_top = top + offset_y;
        this.position(moved_top);
        if (this.onmousemove) { this.onmousemove(move_event, this); }
      }.bind(this);

      if (this.onmousedown) { this.onmousedown(event, this); }
      return false;
    }.bindAsEventListener(this));

    Event.observe(document, 'mousemove', function(event) {
      if (this._move) {
        Event.stop(event);
        this._move(event);
        return false;
      }
    }.bindAsEventListener(this));

    Event.observe(document, 'mouseup', function(event) {
      if (this._move) {
        Event.stop(event);
        this._move = null;
        if (this.onmouseup) { this.onmouseup(event, this); }
        return false;
      }
    }.bindAsEventListener(this));
  },

  listen_wheel: function(element) {
    element = $(element);

    if (this._move) {
      this._move = null;
      if (this.onmouseup) { this.onmouseup(null, this); }
    }

    var handler = function(e) {
      var delta = null;

      if (e.wheelDelta) {
        delta = e.wheelDelta / 120;
      } else if (e.detail) {
        delta = -e.detail / 3;
      }

      if (delta) {
        var pos = this.position();
        this.position(pos - (delta * this.wheel_increment));
        if (this.onmousemove) { this.onmousemove(e, this); }
      }
    }.bindAsEventListener(this);

    if (!window.opera && element.addEventListener) {
      element.addEventListener('DOMMouseScroll', handler, false);
    } else {
      Event.observe(element, 'mousewheel', handler);
    }
  },

  position: function() {
    if (arguments.length > 0) {
      var top = arguments[0];

      if ((top + this.knob.height) > this.bar.height) {
        top = this.bar.height - this.knob.height;
      } else if (top < 0) {
        top = 0;
      }

      Element.setStyle(this.knob, { top:(top + 'px') });
    }

    return (parseInt(Element.getStyle(this.knob, 'top')) || 0);
  }
}
    </script>
  </head>
  <body>
    <table><tbody><tr>
      <td>
        <div id="foo" style="width:200px; height:150px; border:1px solid black;">
          ここでホイールを回す
        </div>
      </td>
      <td>
        <div id="my_scroll" style="width:10px; height:160px; background-color:#EEE;">
          <div style="position:relative; width:10px; height:30px; background-color:#CCC;">
          </div>
        </div>
        <div id="console">0</div>
      </td>
    </tr></tbody></table>
    <script type="text/javascript">
      (function() {
        var scrollbar = new ScrollBar('my_scroll');
        scrollbar.listen_wheel('foo');
        //scrollbar.snap = 13;
        //scrollbar.wheel_increment = 13;
        scrollbar.onmousemove = function(e, self) {
          $('console').innerHTML = self.position();
        }
        scrollbar.onmousedown = function(e, self) {
          Element.setStyle(self.knob, { backgroundColor:'#BBB' });
        }
        scrollbar.onmouseup = function(e, self) {
          Element.setStyle(self.knob, { backgroundColor:'#CCC' });
        }
      })();
    </script>
  </body>
</html>