Pull to refresh

Kinetic ScrollBar

Reading time4 min
Views14K
Эффект кинетической прокрутки сейчас можно встретить практически везде. Это действительно удобно при управлении пальцами или стилусом и довольно забавно при прокрутке мышкой.

В вебе такой эффект пока только приживается. Да и не так уж просто придумать, где он будет удобен… В голову приходят пожалуй лишь scroll bar’ы, которые используются для прокрутки некоторого контента, в основном картинок, внутри страницы. Для примера, можно посмотреть реализацию галереи практически на любом сайте. Согласитесь, было бы значительно интереснее, если бы ползунок не останавливался сразу, как только отпустили кнопку мыши, а продолжал бы двигаться дальше по инерции, постепенно останавливаясь…
Я попытаюсь рассмотреть процесс создания такого эффекта «кинетического» scroll bar’a. Что получилось в итоге можно посмотреть здесь

Алгоритм


Для начала, рассмотрим общий алгоритм (перетаскивание ползунка + «допрокрутка»). Он, на удивление, простой:
  • Отловить mouseDown на объекте, запомнить координаты нажатия.
  • Отслеживать mouseMove. Если был клик (пункт 1), перенести объект на новое место, в противном случае ничего не делать.
  • Замерить скорость. Достаточно просто определить dx: изменение координаты x объекта за одно событие mouseMove.
  • Отловить mouseUp. На основе последнего найденного dx, можно рассчитать некоторый импульс и найти расстояние, до которого нужно перенести объект.
  • Используя формулы затухания, анимировать перемещение объекта на нужное расстояние.

Как видно, все довольно просто. Очевидно, что подобный алгоритм универсален и подходит не только для JS…

Реализация


Для удобства можно использовать библиотеку jQuery и easing эффекты из jQuery UI.
HTML код будет следующим:
<div id="track">
  <div id="thumb"></div>
</div>

Где track – область, в которой бегает ползунок, а thumb – сам ползунок.
CSS:
#track {
  width: 500px;
  position: relative;
  display: block;
  height: 22px;
  margin: 20px;
  border: solid 1px #000;
  overflow: hidden;
}

#track #thumb {
  width: 70px;
  height: 22px;
  position: absolute;
  background-color: gray;
  left: 200px;
}

Теперь можно перейти к написанию самого скрипта. Писать я буду в обычном процедурном стиле, поскольку это учебный пример… при желании можно переписать на прототипах или оформить в виде jQuery плагина.
Введем следующие глобальные переменные:
  1. $track (jQuery объект) – область scroll bar’a
  2. $thumb (jQuery объект) – ползунок
  3. isClicked (bool) – переменная, определяющая кликнули по ползунку или нет.
  4. clickPointX (int) – x координта клика на объекте
  5. dx (int) – изменение координаты x объекта за одно событие mouseMove.
var $track = $('#track');
var $thumb = $('#thumb');        

var isClicked = false;
var clickPointX = 0;
var dx = 0;

Первым делом запретим некоторым рыжим браузерам пытаться перетаскивать наш ползунок:
$thumb.bind('dragstart',  false);

Обрабатываем mouseDown на объекте:
$thumb.mousedown( function(e) {
  // Координаты клика на объекте
  clickPointX = e.pageX - $(this).offset().left;
  isClicked = true;

  $thumb.stop(); // Останавливаем анимацию ползунка
});

Обрабатываем mouseMove, но уже не на объекте, а на всем документе
$(document).mousemove( function(e) {
  if (isClicked) {
    // Новое положение ползунка, в зависимости от текущих
    // координат мыши
    var x = (e.pageX - $track.offset().left - clickPointX);

    // Входит ли ползунок в границы области 
    if (x < -maxBorderOut) {
      x = -maxBorderOut;
    }
    if ( (x + $thumb.width()) > ($track.width() + maxBorderOut)) {
      x = $track.width() - $thumb.width() + maxBorderOut; 
    }

    // Текущее положение
    var selfLeft = parseInt($thumb.css('left'));

    $thumb.css({'left': x + 'px' }); 

    dx = x - selfLeft;
  }
});

Здесь встречается необъявленная переменная maxBorderOut, которая обозначает максимальное количество пикселей, на которое можно утащить ползунок за границы области.
И, наконец, mouseUp:
$(document).mouseup( function(e) {
  if (isClicked) {

    if (Math.abs(dx) < lapse) {
      dx = 0;
    }          

    var selfLeft = parseInt($thumb.css('left'));

    // Новое положение ползунка
    // "impulse * dx" как раз та величина, на которую необходимо доскроллить 
    var x = (selfLeft + impulse * dx);

    // Проверка, не выходит ли ползунок за границы области scroll box'a
    if (x < 0) {
      x = 0;
    }
    if ( (x + $thumb.width()) > $track.width() ) {
      x = $track.width() - $thumb.width(); 
    }

    // Сама анимация перемещения
    $thumb.stop().animate({'left': x + 'px'}, speed, 'easeOutQuart');
  }
  isClicked = false;

});

Переменная lapse определяет некоторую погрешность. То есть, если dx меньше чем эта погрешность, то анимация не происходит. Величина подбиралась на глаз, и может быть выбрана не совсем удачно.
Переменная impulse – величина некоторого импульса воздействующего на ползунок, и определяющего расстояние необходимое для перемещения. По сути, коэффициент умножающийся на dx. Подбирался так же на глаз.
Speed – скорость анимации.
Изменяя значения этих параметров, scroll bar можно настроить под конкретные нужды. При необходимости, сделать вертикальный скролл не должно составить труда.

Заключение


Здесь рассмотрена не полноценная реализация scroll bar’a, а лишь та часть, которая отвечает непосредственно за перетаскивание и «кинетическую» прокрутку. Код получился довольно простой, а эффект весьма интересный.
Использовать можно, к примеру, при реализации постраничной навигации, галереи изображений и т.п…

UPD Сделал jQuery плагин, скачать можно здесь. Как работает, можно посмотреть на примере простенькой карусели

Использовать довольно просто:
<div id="track"></div>

$('#track').kineticBar()
Tags:
Hubs:
+14
Comments20

Articles