ninetails
4/30/2014 - 10:57 PM

iOS wheel select like in HTML5

iOS wheel select like in HTML5

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">
<title>Test</title>
<style>
body {
  font: 400 12px/16px Arial, Helvetica, Sans-serif;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

.container {
  overflow: hidden;
  *zoom: 1;
  display: block;
  float: left;
  position: relative;
  width: 57px;
}
.container .wheel {
  background-image: -webkit-linear-gradient(#aaaaaa, #eeeeee 20%, #eeeeee 80%, #aaaaaa);
  background-image: -webkit-gradient(linear, left top, left bottom, from(#aaaaaa), color-stop(20%, #eeeeee), color-stop(80%, #eeeeee), to(#aaaaaa));
  background-image: linear-gradient(#aaaaaa, #eeeeee 20%, #eeeeee 80%, #aaaaaa);
  border: 1px solid #aaaaaa;
  border-radius: 5px;
  height: 90px;
  overflow: hidden;
  margin: 0 5px;
  width: 45px;
}
.container .wheel ul {
  position: absolute;
  width: 45px;
  top: 30px;
}
.container .wheel li {
  color: #333333;
  display: block;
  text-align: center;
}
.container .wheel li a {
  display: block;
  padding: 7px 0;
}
.container .glass {
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid #aaaaaa;
  border-radius: 5px;
  display: block;
  height: 20px;
  position: absolute;
  top: 33px;
  width: 55px;
}

</style>
</head>
<body>
<div class="container">
  <div class="wheel">
    <ul>
      <li value="2014-04-25">
        <a href="#">25.abr</a>
      </li>
      <li value="2014-04-26">
        <a href="#">26.abr</a>
      </li>
      <li value="2014-04-27">
        <a href="#">27.abr</a>
      </li>
      <li value="2014-04-28">
        <a href="#">28.abr</a>
      </li>
      <li value="2014-04-29">
        <a href="#">29.abr</a>
      </li>
      <li value="2014-04-30">
        <a href="#">30.abr</a>
      </li>
      <li value="2014-05-01">
        <a href="#">01.mai</a>
      </li>
      <li value="2014-05-02">
        <a href="#">02.mai</a>
      </li>
      <li value="2014-05-03">
        <a href="#">03.mai</a>
      </li>
      <li value="2014-05-04">
        <a href="#">04.mai</a>
      </li>
      <li value="2014-05-05">
        <a href="#">05.mai</a>
      </li>
    </ul>
  </div>
  <div class="glass"></div>
</div>
<div class="content">
  <ul>
    <li value="2014-04-25">25 abr</li>
    <li value="2014-04-26">26 abr</li>
    <li value="2014-04-27">27 abr</li>
    <li value="2014-04-28">28 abr</li>
    <li value="2014-04-29">29 abr</li>
    <li value="2014-04-30">30 abr</li>
    <li value="2014-05-01">01 mai</li>
    <li value="2014-05-02">02 mai</li>
    <li value="2014-05-03">03 mai</li>
    <li value="2014-05-04">04 mai</li>
    <li value="2014-05-05">05 mai</li>
  </ul>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script>

(function ($) {
  var wheel = {
    $el: $('.wheel'),
    item_height: 0,
    total: 0,
    v: 0,
    y: 0,
    last: null,
    get_list: function () {
      return this.$el.children('ul');
    },
    get_top: function () {
      return this.get_list().offset().top - this.$el.offset().top;
    },
    get_step: function () {
      var wh = this.$el.outerHeight();

      if (this.y < 0.5 * wh && this.get_top() >= this.item_height || this.y > 0.5 * wh && this.get_top() <= (-1) * (this.total - 2) * this.item_height) {
        return '+=0';
      }
      if (this.y < 0.40 * wh) {
        return '+=' + this.item_height + 'px';
      }
      if (this.y > 0.60 * wh) {
        return '-=' + this.item_height + 'px';
      }
      return '+=0';
    },
    get_duration: function () {
      var wh = this.$el.outerHeight();

      if (this.y < 0.10 * wh || this.y > 0.90 * wh) {
        return 300;
      }
      if (this.y < 0.30 * wh || this.y > 0.70 * wh) {
        return 500;
      }

      return 1000;
    },
    move: function () {
      this.get_list().stop().animate({top: this.get_step()}, {duration: this.get_duration(), complete: $.proxy(this.move, this)});
      this.select_date();
    },
    stop: function () {
      var top = Math.round(this.get_top() / this.item_height) * this.item_height;
      this.get_list().stop().animate({top: top}, 'fast', 'swing', $.proxy(this.select_date, this));
    },
    mousewheel: function (e) {
      var e = window.event || e, // old IE support
        delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))),
        step = (-1) * delta * this.item_height,
        top;

      if (! this.get_list().is(':animated')) {
        if (delta < 0 && this.get_top() >= this.item_height || delta > 0 && this.get_top() <= (-1) * (this.total - 2) * this.item_height) {
          step = 0;
        }

        if (step !== 0) {
          step = (step < 0 ? '-=' : '+=') + Math.abs(step) ;
        } else {
          step = '+=0';
        }

        this.get_list().animate({top: step}, {duration: 500, complete: $.proxy(this.select_date, this)});
      }
    },
    select_date: function () {
      var idx = (-1) * (parseInt(this.get_top() / this.item_height, 10) - 1),
        value = this.$el.find('li').eq(idx).attr('value');

      if (this.last !== idx) {

        $( '.content li:visible' ).hide();
        if ($( ".content li[value='" + value + "']" ).length > 0) {
          $( ".content li[value='" + value + "']" ).show();
        }

        this.last = idx;
      }
    },
    set_start_date: function (date) {
      var items = this.$el.find('li'),
        list = this.get_list(),
        item_height = this.item_height,
        callback = $.proxy(this.select_date, this);

      items.each(function (idx) {
        if ($(this).data('date').toDateString() == date.toDateString() || $(this).data('date') > date || $(this).is(':last-child')) {
          list.css('top', (item_height - $(this).offset().top + $(this).parent().offset().top) + 'px');
          callback();
          return false;
        }
      }) ;
    },
    prepare: function () {
      var glass = this.$el.siblings('.glass').get(0),
        has_touch =  !!("ontouchstart" in window) || window.navigator.msMaxTouchPoints > 0;

      $( '.content li:visible' ).hide();

      this.item_height = this.$el.find('li:first').outerHeight();
      this.total = this.$el.find('li').length;
      this.$el.find('li').each(function(){
        $(this).data('date', new Date($(this).attr('value') + 'T00:00:00-0300'));
      });
      this.set_start_date(new Date());

      // muda velocidade
      this.$el.bind('mousemove', $.proxy(function(e) {
        this.set_mouse_y(e);
      }, this));

      // mouse wheel
      if (glass.addEventListener) {
        glass.addEventListener('mousewheel', $.proxy(this.mousewheel, this), false);
        glass.addEventListener('DOMMouseScroll', $.proxy(this.mousewheel, this), false);
      } else {
        glass.attachEvent('onmousewheel', $.proxy(this.mousewheel, this));
      }


      // hover ou touch
      if (!has_touch) {
        // hover
        this.$el.hover($.proxy(function(e) {
          this.set_mouse_y(e);
          this.move();
        }, this), $.proxy(function(e) {
          this.set_mouse_y(e);
          this.stop();
        }, this));
      } else {
        // touch
        var start_y, last_y, touch_top;
        this.$el.bind('touchstart', $.proxy(function(e) {
          e.preventDefault();
          start_y = e.originalEvent.touches[0].pageY;
          touch_top = this.get_top();
        }, this));
        this.$el.bind('touchmove', $.proxy(function(e) {
          e.preventDefault();
          last_y = e.originalEvent.touches[0].pageY;
          this.get_list().css('top', touch_top - start_y + last_y);
        }, this));
        this.$el.bind('touchend', $.proxy(function(e) {
          var top = Math.round((touch_top - start_y + last_y) / this.item_height) * this.item_height;
          top = Math.max(top, (-1) * (this.total - 2) * this.item_height);
          top = Math.min(top, this.item_height);
          e.preventDefault();
          this.get_list().stop().animate({top: top}, 'fast', 'swing', $.proxy(this.select_date, this));
        }, this));
      }
    },
    touch_drag: function(e) {
      this.get_list().css('top', (item_height - $(this).offset().top + $(this).parent().offset().top) + 'px');
    },
    set_mouse_y: function (e) {
      this.y = e.pageY - this.$el.offset().top;
    }
  } ;

  $(function () {
    wheel.prepare();
  });
}).apply(this, [jQuery]);

</script>
</body></html>