jQuery を用いて大きな画像などを Google Map ライクにスクロール表示する UI

下記のサンプルは jQuery プラグインとして公開しています。(2009/05/20 追記)
jquery-scrollview - This jQuery plugin applies grab-and-drag scroll view to block elements. - Google Project Hosting

壁紙などの大きなサイズの画像を表示するのに Google マップのようなインターフェイスを提供したい。
Google マップのような、

  • マウスドラッグでスクロール
  • ダブルクリックした所にセンタリング

するような処理である。ただ、ズームに関しては実装しない。
ということで実装したサンプルは ScrollViewer Sample である。

ScrollViewer

jQuery を必要とする。

function ScrollViewer(){
        this.initialize.apply(this, arguments); 
}
ScrollViewer.prototype = {
        initialize: function(container){
                //
                // Dragging Cursor Set.
                //
                // http://docs.jquery.com/Utilities/jQuery.browser
                // jQuery.browser Deprecated in jQuery 1.3
                //
                if (navigator.userAgent.indexOf("Gecko/") != -1) {
                        this.grab = "-moz-grab";
                        this.grabbing = "-moz-grabbing";
                } else {
                        this.grab = "default";
                        this.grabbing = "move";
                }

                // Get container and image.
                this.m = $(container);
                this.i = this.m.children().css("cursor", this.grab);
                
                this.isgrabbing = false;

                // Set mouse events.
                var self = this;
                this.i.mousedown(function(e){
                        self.startgrab();
                        this.xp = e.pageX;
                        this.yp = e.pageY;
                        return false;
                }).mousemove(function(e){
                        if (!self.isgrabbing) return true;
                        self.scrollTo(this.xp - e.pageX, this.yp - e.pageY);
                        this.xp = e.pageX;
                        this.yp = e.pageY;
                        return false;
                })
                .mouseout(function(){ self.stopgrab() })
                .mouseup(function(){ self.stopgrab() })
                .dblclick(function(){
                        var _m = self.m;
                        var off = _m.offset();
                        var dx = this.xp - off.left - _m.width() / 2;
                        if (dx < 0) {
                                dx = "+=" + dx + "px";
                        } else {
                                dx = "-=" + -dx + "px";
                        }
                        var dy = this.yp - off.top - _m.height() / 2;
                        if (dy < 0) {
                                dy = "+=" + dy + "px";
                        } else {
                                dy = "-=" + -dy + "px";
                        }
                        _m.animate({ scrollLeft:  dx, scrollTop: dy },
                                "normal", "swing");
                });
                
                this.centering();
        },
        centering: function(){
                var _m = this.m;
                var w = this.i.width() - _m.width();
                var h = this.i.height() - _m.height();
                _m.scrollLeft(w / 2).scrollTop(h / 2);
        },
        startgrab: function(){
                this.isgrabbing = true;
                this.i.css("cursor", this.grabbing);
        },
        stopgrab: function(){
                this.isgrabbing = false;
                this.i.css("cursor", this.grab);
        },
        scrollTo: function(dx, dy){
                var _m = this.m;
                var x = _m.scrollLeft() + dx;
                var y = _m.scrollTop() + dy;
                _m.scrollLeft(x).scrollTop(y);
        }
}

※ ダブルクリックでのセンタリング時はスムーズにスクロールする。
Firefox(Gecko) はマウスカーソルに[握る]アイコンがあるため、そちらを割り当てている。なお、jQuery 1.3 から jQuery.browser は使用しない方がいいようだ。

使い方

コンテナとなるブロック要素を指定して、ScrollViewerのコンストラクタを呼び出すだけ。(サンプルは画像になっているが制限しているわけではない。)

<script src="jquery-1.3.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
  var viewer = new ScrollViewer("#image"));
});
</script>
</head>
<body>
<h1>ScrollViewer Sample</h1>
<div id="image">
 <img src="xxxxxxxxx.jpg" width="1024" height="768" />
</div>
</body>