title: Touch-scroll Jquery Plugin - How to Init with different options for multiple instances?
body: <p>As found here - <a href="https://github.com/neave/touch-scroll" rel="nofollow">https://github.com/neave/touch-scroll</a>:</p>
  
  <pre><code>(function($) {
  
  // Define default scroll settings
  var defaults = {
      y: 0,
      scrollHeight: 0,
      elastic: !navigator.userAgent.match(/android/i),
      momentum: true,
      elasticDamp: 0.6,
      elasticTime: 50,
      reboundTime: 400,
      momentumDamp: 0.9,
      momentumTime: 300,
      iPadMomentumDamp: 0.95,
      iPadMomentumTime: 1200,
      touchTags: ['select', 'input', 'textarea']
  };
  
  // Define methods
  var methods = {
  
      init: function(options) {
          return this.each(function() {
  
              var o = $.extend(defaults, options);
  
              // Prevent double-init, just update instead
              if (!!this._init) {
                  return this.update();
              }
              this._init = true;
  
              // Define element variables
              var $this = $(this),
                  scrollY = -o.y,
                  touchY = 0,
                  movedY = 0,
                  pollY = 0,
                  height = 0,
                  maxHeight = 0,
                  scrollHeight = 0,
                  scrolling = false,
                  bouncing = false,
                  moved = false,
                  timeoutID,
                  isiPad = !!navigator.platform.match(/ipad/i),
                  hasMatrix = 'WebKitCSSMatrix' in window,
                  has3d = hasMatrix &amp;&amp; 'm11' in new WebKitCSSMatrix();
  
              // Keep bottom of scroll area at the bottom on resize
              var update = this.update = function() {
                  height = $this.height();
                  if (o.scrollHeight) {
                      scrollHeight = o.scrollHeight;
                  } else if ($this.prop) {
                      scrollHeight = $this.prop('scrollHeight'); // jQuery 1.6 uses .prop(), older versions use .attr()
                  } else {
                      scrollHeight = $this.attr('scrollHeight');
                  }
                  if (scrollHeight &lt; height) {
                      scrollHeight = height;
                  }
                  maxHeight = height - scrollHeight;
                  clearTimeout(timeoutID);
                  clampScroll(false);
              };
  
              // Set up initial variables
              update();
  
              // Set up transform CSS
              $this.css({'-webkit-transition-property': '-webkit-transform',
                  '-webkit-transition-timing-function': 'cubic-bezier(0,0,0.2,1)',
                  '-webkit-transition-duration': '0',
                  '-webkit-transform': cssTranslate(scrollY)});
  
              // Listen for screen size change event
              window.addEventListener('onorientationchange' in window ? 'orientationchange' : 'resize', update, false);
  
              // Listen for touch events
              $this.bind('touchstart.touchScroll', touchStart);
              $this.bind('touchmove.touchScroll', touchMove);
              $this.bind('touchend.touchScroll touchcancel.touchScroll', touchEnd);
              $this.bind('webkitTransitionEnd.touchScroll', transitionEnd);
  
              // Set the position of the scroll area using transform CSS
              var setPosition = this.setPosition = function(y) {
                  scrollY = y;
                  $this.css('-webkit-transform', cssTranslate(scrollY));
              };
  
              // Transform using a 3D translate if available
              function cssTranslate(y) {
                  return 'translate' + (has3d ? '3d(0,' : '(0,') + y + 'px' + (has3d ? ',0)' : ')');
              }
  
              // Set CSS transition time
              function setTransitionTime(time) {
                  time = time || '0';
                  $this.css('-webkit-transition-duration', time + 'ms');
              }
  
              // Get the actual pixel position made by transform CSS
              function getPosition() {
                  if (hasMatrix) {
                      var transform = window.getComputedStyle($this[0]).webkitTransform;
                      if (!!transform &amp;&amp; transform !== 'none') {
                          var matrix = new WebKitCSSMatrix(transform);
                          return matrix.f;
                      }
                  }
                  return scrollY;
              }
  
              // Expose getPosition API
              this.getPosition = function() {
                  return getPosition();
              };
  
              // Bounce back to the bounds after momentum scrolling
              function reboundScroll() {
                  if (scrollY &gt; 0) {
                      scrollTo(0, o.reboundTime);
                  } else if (scrollY &lt; maxHeight) {
                      scrollTo(maxHeight, o.reboundTime);
                  }
              }
  
              // Stop everything once the CSS transition in complete
              function transitionEnd() {
                  if (bouncing) {
                      bouncing = false;
                      reboundScroll();
                  }
  
                  clearTimeout(timeoutID);
              }
  
              // Limit the scrolling to within the bounds
              function clampScroll(poll) {
                  if (!hasMatrix || bouncing) {
                      return;
                  }
  
                  var oldY = pollY;
                  pollY = getPosition();
  
                  if (pollY &gt; 0) {
                      if (o.elastic) {
                          // Slow down outside top bound
                          bouncing = true;
                          scrollY = 0;
                          momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
                      } else {
                          // Stop outside top bound
                          setTransitionTime(0);
                          setPosition(0);
                      }
                  } else if (pollY &lt; maxHeight) {
                      if (o.elastic) {
                          // Slow down outside bottom bound
                          bouncing = true;
                          scrollY = maxHeight;
                          momentumScroll(pollY - oldY, o.elasticDamp, 1, height, o.elasticTime);
                      } else {
                          // Stop outside bottom bound
                          setTransitionTime(0);
                          setPosition(maxHeight);
                      }
                  } else if (poll) {
                      // Poll the computed position to check if element is out of bounds
                      timeoutID = setTimeout(clampScroll, 20, true);
                  }
              }
  
              // Animate to a position using CSS
              function scrollTo(destY, time) {
                  if (destY === scrollY) {
                      return;
                  }
  
                  moved = true;
                  setTransitionTime(time);
                  setPosition(destY);
              }
  
              // Perform a momentum-based scroll using CSS
              function momentumScroll(d, k, minDist, maxDist, t) {
                  var ad = Math.abs(d),
                      dy = 0;
  
                  // Calculate the total distance
                  while (ad &gt; 0.1) {
                      ad *= k;
                      dy += ad;
                  }
  
                  // Limit to within min and max distances
                  if (dy &gt; maxDist) {
                      dy = maxDist;
                  }
                  if (dy &gt; minDist) {
                      if (d &lt; 0) {
                          dy = -dy;
                      }
  
                      dy += scrollY;
  
                      // If outside the bounds, don't go too far
                      if (height &gt; 0) {
                          if (dy &gt; height * 2) {
                              var ody = dy;
                              dy = height * 2;
                          } else if (dy &lt; maxHeight - height * 2) {
                              dy = maxHeight - height * 2;
                          }
                      }
  
                      // Perform scroll
                      scrollTo(Math.round(dy), t);
                  }
  
                  clampScroll(true);
              }
  
              // Get the touch points from this event
              function getTouches(e) {
                  if (e.originalEvent) {
                      if (e.originalEvent.touches &amp;&amp; e.originalEvent.touches.length) {
                          return e.originalEvent.touches;
                      } else if (e.originalEvent.changedTouches &amp;&amp; e.originalEvent.changedTouches.length) {
                          return e.originalEvent.changedTouches;
                      }
                  }
                  return e.touches;
              }
  
              // Dispatches a fake mouse event from a touch event
              function dispatchMouseEvent(name, touch, target) {
                  var e = document.createEvent('MouseEvent');
                  e.initMouseEvent(name, true, true, touch.view, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
                  target.dispatchEvent(e);
              }
  
              // Find the root node of this target
              function getRootNode(target) {
                  while (target.nodeType !== 1) {
                      target = target.parentNode;
                  }
                  return target;
              }
  
              // Perform a touch start event
              function touchStart(e) {
                  // Allow certain HTML tags to receive touch events
                  if ($.inArray(e.target.tagName.toLowerCase(), o.touchTags) !== -1) {
                      return;
                  }
  
                  // Stop the default touches
                  e.preventDefault();
                  e.stopPropagation();
  
                  var touch = getTouches(e)[0];
  
                  // Dispatch a fake mouse down event     
                  dispatchMouseEvent('mousedown', touch, getRootNode(touch.target));
  
                  scrolling = true;
                  moved = false;
                  movedY = 0;
  
                  clearTimeout(timeoutID);
                  setTransitionTime(0);
  
                  // Check scroll position
                  if (o.momentum) {
                      var y = getPosition();
                      if (y !== scrollY) {
                          setPosition(y);
                          moved = true;
                      }
                  }
  
                  touchY = touch.pageY - scrollY;
              }
  
              // Perform a touch move event
              function touchMove(e) {
                  if (!scrolling) {
                      return;
                  }
  
                  var dy = getTouches(e)[0].pageY - touchY;
  
                  // Elastic-drag or stop when moving outside of boundaries
                  if (dy &gt; 0) {
                      if (o.elastic) {
                          dy /= 2;
                      } else {
                          dy = 0;
                      }
                  } else if (dy &lt; maxHeight) {
                      if (o.elastic) {
                          dy = (dy + maxHeight) / 2;
                      } else {
                          dy = maxHeight;
                      }
                  }
  
                  movedY = dy - scrollY;
                  moved = true;
                  setPosition(dy);
              }
  
              // Perform a touch end event
              function touchEnd(e) {
                  if (!scrolling) {
                      return;
                  }
  
                  scrolling = false;
  
                  if (moved) {
                      // Ease back to within boundaries
                      if (scrollY &gt; 0 || scrollY &lt; maxHeight) {
                          reboundScroll();
                      } else if (o.momentum) {
                          // Free scroll with momentum
                          momentumScroll(movedY, isiPad ? o.iPadMomentumDamp : o.momentumDamp, 40, 2000, isiPad ? o.iPadMomentumTime : o.momentumTime);
                      }           
                  } else {
                      var touch = getTouches(e)[0],
                          target = getRootNode(touch.target);
  
                      // Dispatch fake mouse up and click events if this touch event did not move
                      dispatchMouseEvent('mouseup', touch, target);
                      dispatchMouseEvent('click', touch, target);
                  }
              }
  
          });
      },
  
      update: function() {
          return this.each(function() {
              this.update();
          });
      },
  
      getPosition: function() {
          var a = [];
          this.each(function() {
              a.push(-this.getPosition());
          });
          return a;
      },
  
      setPosition: function(y) {
          return this.each(function() {
              this.setPosition(-y);
          });
      }
  
  };
  
  // Public method for touchScroll
  $.fn.touchScroll = function(method) {
      if (methods[method]) {
          return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
      } else if (typeof method === 'object' || !method) {
          return methods.init.apply(this, arguments);
      } else {
          $.error('Method ' +  method + ' does not exist on jQuery.touchScroll');
      }
  };
  
  })(jQuery);
  </code></pre>
  
  <p>How to make this work on multiple instances with different selectors and unique options for each like this?:</p>
  
  <pre><code>$('#selector1').touchScroll({elastic: false});
  $('#selector2').touchScroll({elastic: true});
  </code></pre>
  
  <p>Currently options set in either override the other.</p>