Advertisement
Guest User

touch-scroll.js

a guest
Jan 24th, 2011
1,017
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function($) {
  2.    
  3.     // Define default scroll settings
  4.     var defaults = {
  5.         y: 0,
  6.         elastic: true,
  7.         momentum: true,
  8.         elasticDamp: 0.6,
  9.         elasticTime: 50,
  10.         reboundTime: 400,
  11.         momentumDamp: 0.9,
  12.         momentumTime: 300,
  13.         iPadMomentumDamp: 0.95,
  14.         iPadMomentumTime: 1200,
  15.         selects: {}
  16.     };
  17.    
  18.     // Define methods
  19.     var methods = {
  20.        
  21.         init: function(options) {
  22.  
  23.             return this.each(function() {
  24.  
  25.                 // Define element variables
  26.                 var $this = $(this),
  27.                     o = $.extend(defaults, options),
  28.                     scrollY = -o.y,
  29.                     touchY = 0,
  30.                     movedY = 0,
  31.                     pollY = 0,
  32.                     height = 0,
  33.                     maxHeight = 0,
  34.                     scrollHeight = $this.attr('scrollHeight'),
  35.                     scrolling = false,
  36.                     bouncing = false,
  37.                     moved = false,
  38.                     timeoutID,
  39.                     isiPad = navigator.platform.indexOf('iPad') !== -1,
  40.                     hasMatrix = 'WebKitCSSMatrix' in window,
  41.                     has3d = hasMatrix && 'm11' in new WebKitCSSMatrix();
  42.                
  43.                 // Set up initial variables
  44.                 update();
  45.                
  46.                 // Set up transform CSS
  47.                 $this.css({'-webkit-transition-property': '-webkit-transform',
  48.                     '-webkit-transition-timing-function': 'cubic-bezier(0, 0, 0.2, 1)',
  49.                     '-webkit-transition-duration': '0',
  50.                     '-webkit-transform': cssTranslate(scrollY)});
  51.                
  52.                 // Listen for screen size change event
  53.                 window.addEventListener('onorientationchange' in window ? 'orientationchange' : 'resize', update, false);
  54.                
  55.                 // Listen for touch events
  56.                 $this.bind('touchstart.touchScroll', touchStart);
  57.                 $this.bind('touchmove.touchScroll', touchMove);
  58.                 $this.bind('touchend.touchScroll touchcancel.touchScroll', touchEnd);
  59.                 $this.bind('webkitTransitionEnd.touchScroll', transitionEnd);
  60.                
  61.                 // Set the position of the scroll area using transform CSS
  62.                 var setPosition = this.setPosition = function(y) {
  63.                     scrollY = y;
  64.                     $this.css('-webkit-transform', cssTranslate(scrollY));
  65.                 };
  66.                
  67.                 // Transform using a 3D translate if available
  68.                 function cssTranslate(y) {
  69.                     return 'translate' + (has3d ? '3d(0px, ' : '(0px, ') + y + 'px' + (has3d ? ', 0px)' : ')');
  70.                 }
  71.                
  72.                 // Keep bottom of scroll area at the bottom on resize
  73.                 function update() {
  74.                     height = $this.height();
  75.                     maxHeight = height - scrollHeight;
  76.                     clearTimeout(timeoutID);
  77.                     clampScroll(false);
  78.                 }
  79.  
  80.                 // Set CSS transition time
  81.                 function setTransitionTime(time) {
  82.                     time = time || '0';
  83.                     $this.css('-webkit-transition-duration', time + 'ms');
  84.                 }
  85.  
  86.                 // Get the actual pixel position made by transform CSS
  87.                 function getComputedScrollY() {
  88.                     if (hasMatrix) {
  89.                         var matrix = new WebKitCSSMatrix(window.getComputedStyle($this[0]).webkitTransform);
  90.                         return matrix.f;
  91.                     }
  92.                     return scrollY;
  93.                 }
  94.  
  95.                 // Bounce back to the bounds after momentum scrolling
  96.                 function reboundScroll() {
  97.                     if (scrollY > 0) {
  98.                         scrollTo(0, o.reboundTime);
  99.                     } else if (scrollY < maxHeight) {
  100.                         scrollTo(maxHeight, o.reboundTime);
  101.                     }
  102.                 }
  103.  
  104.                 // Stop everything once the CSS transition in complete
  105.                 function transitionEnd() {
  106.                     if (bouncing) {
  107.                         bouncing = false;
  108.                         reboundScroll();
  109.                     }
  110.  
  111.                     clearTimeout(timeoutID);
  112.                 }
  113.                
  114.                 // Limit the scrolling to within the bounds
  115.                 function clampScroll(poll) {
  116.                     if (!hasMatrix || bouncing) {
  117.                         return;
  118.                     }
  119.  
  120.                     var oldY = pollY;
  121.                     pollY = getComputedScrollY();
  122.                    
  123.                     if (pollY > 0) {
  124.                         if (o.elastic) {
  125.                             // Slow down outside top bound
  126.                             bouncing = true;
  127.                             scrollY = 0;
  128.                             momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
  129.                         } else {
  130.                             // Stop outside top bound
  131.                             setTransitionTime(0);
  132.                             setPosition(0);
  133.                         }
  134.                     } else if (pollY < maxHeight) {
  135.                         if (o.elastic) {
  136.                             // Slow down outside bottom bound
  137.                             bouncing = true;
  138.                             scrollY = maxHeight;
  139.                             momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
  140.                         } else {
  141.                             // Stop outside bottom bound
  142.                             setTransitionTime(0);
  143.                             setPosition(maxHeight);
  144.                         }
  145.                     } else if (poll) {
  146.                         // Poll the computed position to check if element is out of bounds
  147.                         timeoutID = setTimeout(clampScroll, 20, true);
  148.                     }
  149.                 }
  150.                
  151.                 // Animate to a position using CSS
  152.                 function scrollTo(destY, time) {
  153.                     if (destY === scrollY) {
  154.                         return;
  155.                     }
  156.  
  157.                     moved = true;
  158.                     setTransitionTime(time);
  159.                     setPosition(destY);
  160.                 }
  161.                
  162.                 // Perform a momentum-based scroll using CSS
  163.                 function momentumScroll(d, k, minDist, maxDist, t) {
  164.                     var ad = Math.abs(d),
  165.                         dy = 0;
  166.                    
  167.                     // Calculate the total distance
  168.                     while (ad > 0.1) {
  169.                         ad *= k;
  170.                         dy += ad;
  171.                     }
  172.                    
  173.                     // Limit to within min and max distances
  174.                     if (dy > maxDist) {
  175.                         dy = maxDist;
  176.                     }
  177.                     if (dy > minDist) {
  178.                         if (d < 0) {
  179.                             dy = -dy;
  180.                         }
  181.                        
  182.                         // Perform scroll
  183.                         scrollTo(scrollY + Math.round(dy), t);
  184.                     }
  185.                    
  186.                     clampScroll(true);
  187.                 }
  188.                
  189.                 // Get the touch points from this event
  190.                 function getTouches(e) {
  191.                     if (e.originalEvent) {
  192.                         if (e.originalEvent.touches && e.originalEvent.touches.length) {
  193.                             return e.originalEvent.touches;
  194.                         } else if (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length) {
  195.                             return e.originalEvent.changedTouches;
  196.                         }
  197.                     }
  198.                     return e.touches;
  199.                 }
  200.                
  201.                 // Perform a touch start event
  202.                 function touchStart(e) {
  203.                
  204.                     var selectfield = false;
  205.                     var touches = getTouches(e);
  206.                    
  207.                     o.selects.each(function(index) {
  208.                         var offset = $(this).offset();
  209.                         if (touches[0].pageX > offset.left && touches[0].pageX < offset.left + $(this).width()
  210.                                 && touches[0].pageY > offset.top && touches[0].pageY < offset.top + $(this).height()) {
  211.                             selectfield = true;
  212.                         }
  213.                         if (selectfield) {
  214.                             return;
  215.                         }
  216.                       });
  217.  
  218.                    
  219.                     if (!selectfield) {
  220.                        
  221.                         e.preventDefault();
  222.                         e.stopPropagation();
  223.                        
  224.                         scrolling = true;
  225.                         moved = false;
  226.                         movedY = 0;
  227.                        
  228.                         clearTimeout(timeoutID);
  229.                         setTransitionTime(0);
  230.                        
  231.                         // Check scroll position
  232.                         if (o.momentum) {
  233.                             var y = getComputedScrollY();
  234.                             if (y !== scrollY) {
  235.                                 setPosition(y);
  236.                                 moved = true;
  237.                             }
  238.                         }
  239.    
  240.                         touchY = touches[0].pageY - scrollY;
  241.                     }
  242.                 }
  243.                
  244.                 // Perform a touch move event
  245.                 function touchMove(e) {
  246.                     if (!scrolling) {
  247.                         return;
  248.                     }
  249.                    
  250.                     var touches = getTouches(e),
  251.                         dy = touches[0].pageY - touchY;
  252.                    
  253.                     // Elastic-drag or stop when moving outside of boundaries
  254.                     if (dy > 0) {
  255.                         if (o.elastic) {
  256.                             dy /= 2;
  257.                         } else {
  258.                             dy = 0;
  259.                         }
  260.                     } else if (dy < maxHeight) {
  261.                         if (o.elastic) {
  262.                             dy = (dy + maxHeight) / 2;
  263.                         } else {
  264.                             dy = maxHeight;
  265.                         }
  266.                     }
  267.                    
  268.                     movedY = dy - scrollY;
  269.                     moved = true;
  270.                     setPosition(dy);
  271.                 }
  272.                
  273.                 // Perform a touch end event
  274.                 function touchEnd(e) {
  275.                     if (!scrolling) {
  276.                         return;
  277.                     }
  278.                    
  279.                     scrolling = false;
  280.                    
  281.                     var touches = getTouches(e);
  282.                    
  283.                     if (moved) {
  284.                         // Ease back to within boundaries
  285.                         if (scrollY > 0 || scrollY < maxHeight) {
  286.                             reboundScroll();
  287.                         } else if (o.momentum) {
  288.                             // Free scroll with momentum
  289.                             momentumScroll(movedY, isiPad ? o.iPadMomentumDamp : o.momentumDamp, 40, 2000, isiPad ? o.iPadMomentumTime : o.momentumTime);
  290.                         }          
  291.                     } else {
  292.                         // Dispatch a fake click event if this touch event did not move
  293.                         var touch = touches[0],
  294.                             target = touch.target,
  295.                             me = document.createEvent('MouseEvent');
  296.  
  297.                         while (target.nodeType !== 1) {
  298.                             target = target.parentNode;
  299.                         }
  300.                         me.initMouseEvent('click', true, true, touch.view, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
  301.                         target.dispatchEvent(me);
  302.                     }
  303.                 }
  304.            
  305.             });
  306.         },
  307.        
  308.         // Public method for setPosition
  309.         setPosition: function(y) {
  310.             return this.each(function() {
  311.                 this.setPosition(-y);              
  312.             });
  313.         }
  314.        
  315.     };
  316.    
  317.     // Public method for touchScroll
  318.     $.fn.touchScroll = function(method) {
  319.         if (methods[method]) {
  320.             return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  321.         } else if (typeof method === 'object' || !method) {
  322.             return methods.init.apply(this, arguments);
  323.         } else {
  324.             $.error('Method ' +  method + ' does not exist on jQuery.touchScroll');
  325.         }
  326.     };
  327.  
  328. })(jQuery);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement