第18回 iPhoneのようにページをマウスで掴んではじいてスクロール(フリックスクロール)を実装してみる – jQuery入門

2009 年 10 月 21 日 投稿者: naga3

念願のiPhoneを買ったんです。触ってみると、文字入力やスクロールでのフリック(はじく)操作が心地よいのです。そこでjQueryならフリックによるスクロールも簡単に実装できるんじゃないかな?と思ってやってみました。そういえば昔持っていたFM-TOWNSというパソコンに「猫の手スクロール」というものが流行ってまして、これがまさにフリックスクロールそのものでした。

フリックスクロールのデモ

ウインドウの真ん中あたりでマウスボタンを押したまま上下に動かして離してみてください。ソースが必要ならば右クリックから保存してください。
flick.html(別ウインドウで開きます)
通常のページもフリックスクロール対応にしてみたかったので、ブックマークレットも作りました。このリンク(フリックスクロール)をアドレスバーにドラッグすればjQueryを読み込んでいるページならフリックスクロールします。jQueryが入ってないページはjQuerifyページのブックマークレットを先に実行すればたぶん大丈夫だと思います。

ソース

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.3");</script>

<script type="text/javascript">
$(function() {
    var pushed = false;
    var y = 0;
    var vy = 0;
    var id = 0;
    $('body').mousedown(function(e) {
        $(this).css('cursor', 'n-resize');
        y = e.clientY;
        pushed = true;
        vy = 0;
        return false;
    }).mousemove(function(e) {
        if (pushed) {
            vy = y - e.clientY;
            y = e.clientY;
            $(window).scrollTop($(window).scrollTop() + vy);
        }
        return false;
    }).mouseup(function() {
        $(this).css('cursor', 'auto');
        pushed = false;
        id = setInterval(function() {
            var top = $(window).scrollTop();
            $(window).scrollTop(top + vy);
            if (pushed || top == $(window).scrollTop()) {
                clearInterval(id);
                id = 0;
            }
        }, 10);
        return false;
    });
});
</script>
</head>
<body>
ここにスクロールする長いコンテンツを入れます。
・・・・・・・
</body>
</html>

プログラムの解説

var pushed = false;
var y = 0;
var vy = 0;
var id = 0;
pushedはマウスボタンが押されている間trueになるフラグです。yはマウスの現在位置のy座標、vyは縦方向の速度を保持します。idはタイマのハンドルを保持するための変数です。
$('body').mousedown(function(e) {
    $(this).css('cursor', 'n-resize');
    y = e.clientY;
    pushed = true;
    vy = 0;
    return false;
ドキュメント内でマウスボタンが押されたときのイベントです。まずカーソルを上下方向の矢印にし、変数yにウインドウ最上部からのy座標を入れ、pushedフラグを立てます。
}).mousemove(function(e) {
    if (pushed) {
        vy = y - e.clientY;
        y = e.clientY;
        $(window).scrollTop($(window).scrollTop() + vy);
    }
    return false;
こちらはドキュメント内でマウスが移動したときのイベントですが、まずpushedフラグを見てマウスボタンが押されているときのみ処理しています。処理内容は、ひとつ前のイベントのy座標と現在のy座標の差から速度を割り出し変数vyに代入、その速度分だけウインドウをスクロールさせています。
}).mouseup(function() {
    $(this).css('cursor', 'auto');
    pushed = false;
    id = setInterval(function() {
        ・・・・・・
    }, 10);
    return false;
こちらはマウスボタンが離されたときのイベントです。カーソルを元に戻し、pushedフラグをクリアし、フリック(はじく)スクロールを実現するためにウインドウをスクロールするタイマイベントを10msの間隔で呼び出すように設定しています。タイマイベントの中身は以下の通り。
var top = $(window).scrollTop();
$(window).scrollTop(top + vy);
if (pushed || top == $(window).scrollTop()) {
    clearInterval(id);
    id = 0;
}
マウスが離された瞬間の速度がvyに入っているので、その分量だけウインドウをスクロールさせ、マウスボタンが再度押されるか、またはスクロールがコンテンツの最初や最後で止まったとき、clearIntervalでタイマイベントをクリアしています。

注意点

ブラウザの外に出たりすると動作が変になりますが、対応するとソースが長くなって面倒なのでそのままです。

追記:2009/10/22

加速度が欲しいというコメントがありましたのでiPhoneを見ると、確かに加速度が付いて止まっている!ということで付けてみました。
flick2.html(別ウインドウで開きます)
しかしiPhoneのような気持ち良さを出すのは難しいのです。

この記事へのトラックバックURL

5件のコメント

  1. Tweets that mention 第18回 iPhoneのようにページをマウスで掴んではじいてスクロール(フリックスクロール)を実装してみる – jQuery入門 – ポンクソフト -- Topsy.com より:

    [...] This post was mentioned on Twitter by Nambo, piro_deno. piro_deno said: 等速運動じゃなくて、加速運動の方がよかったかなー。あと、キャンセルも欲しいところ。テキスト選択できないし。。でも、こう [...]

  2. Alyssa より:

    なぁんと快適なフリック感~♪

    加速もつく様に思えました!

    ま・さ・に、iPhoneな滑らかさw


    そして、フリック体験ページの文章にも敢闘賞を・・・

    だってだって、「ええぃ、この翻訳化けはなんぞや???」

    と、スイスイとフリックして最後の一行を確認したくなっちゃぅ~

  3. naga3 より:

    >Alyssa
    加速は忘れてたんで付けてみたー。

    あの翻訳化けテキストは「ダミーテキスト作成」的なサービスがあってそれでつくったものであります。たぶん元ネタは夏目漱石。

  4. cada より:

    naga3もiPhoneにされたのですね!
    僕は20日に契約しました〜仲間ですね-!!

  5. naga3 より:

    なかまなかま~
    iPhoneのGPSの精度がすごくて驚きっぱなし。
    前持ってた携帯は平気で1kmくらいずれてた気がする・・・

コメントをどうぞ