# Scrubbing.js

Highly customizable mouse scrubbing implementation for numbers and custom data.

[More info on GitHub](https://github.com/FWeinb/Scrubbing.js)


## Horizontal 

This is the default behaviour

    new Scrubbing ( document.querySelector ( '#scrubbing-horizontal') );

<p class="center">
  <span class="big" id="scrubbing-horizontal">20</span>
</p>

## Horizontal / with mouse wheel

It is possible to add more than on driver. 

    new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-wheel')
                  , { driver : [ Scrubbing.driver.Mouse,
                                 Scrubbing.driver.MouseWheel,
                                 Scrubbing.driver.Touch
                               ]});

<p class="center">
  <span class="big" id="scrubbing-horizontal-wheel">20</span>
</p>

## Vertical 

You change the scrubbing to vertical by using the passing `'DefaultVertical'` 

    new Scrubbing ( document.querySelector ( '#scrubbing-vertical' )
                  , { resolver : 'DefaultVertical' } );

or using `Scrubbing.resolver.DefaultVertical` 
    
    new Scrubbing ( document.querySelector ( '#scrubbing-vertical' )
                  , { resolver : Scrubbing.resolver.DefaultVertical } );


<p class="center">
  <span class="big" id="scrubbing-vertical">20</span>
</p>


## Vertical / with friction 

By using a the `Scrubbing.resolver.VerticalProvider ( friction )` you can change the `friction` of the Scrubber.

    new Scrubbing ( document.querySelector ( '#scrubbing-vertical-friction' )
                  , { resolver : Scrubbing.resolver.VerticalProvider ( 50 ) } )
                 
<p class="center">
  <span class="big" id="scrubbing-vertical-friction">20</span>
</p>

## Horizontal / with custom Values

By implementing your own `adapter` you can output custome values. 
Here it is a Excel like letter iterator. 

    new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-custom')
                  , { adapter  : MyOwnAdapter 
                    , resolver : Scrubber.resolver.HorizontalProvider ( 30 ) });

<p class="center">
  <span class="big" id="scrubbing-horizontal-custom">B</span>
</p>


## Horizontal / width array values

Another `adapter` could be an ArrayAdapter that would scrub though array values.

    new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-array')
                  , { adapter  : new ArrayAdapter(["Test",  "Test1", "Test2"
                                                  ,"Test3", "Test4", "Test5"
                                                  ,"Test6"])
                    , resolver : Scrubbing.resolver.HorizontalProvider ( 50 )})

<p class="center">
  <span class="big" id="scrubbing-horizontal-array">A</span>
</p>

<footer>
  by <a href="https://twitter.com/FWeinb">Fabrice Weinberg</a> 2014
</footer>
View Compiled
[data-scrub-orientation]{
  border-bottom:1px dashed black; 
}

[data-scrub-orientation="Vertical"]{
  cursor: row-resize;
}

[data-scrub-orientation="Horizontal"]{
  cursor: col-resize;
}


body {
  padding: 0em 1em;
}

.big {
  font-size: 2em;
}

.center{
  margin:0 auto;
  text-align:center;
}


footer{
  text-align:right;
  color:#999; 
  
  a{
    color:#555;
  }
}
View Compiled
/*! Scrubbing 02-01-2014 
 * Fabrice Weinberg 
 */
!function(a,b){var c=function(a,b){return a?"string"==typeof a?b[a]:a:void 0},d=function(a,b,d,e,f){a[f]=b?c(b[f],e)||d[f]:d[f]},e=function(a,b,c,d,e){Array.isArray(a)?a.forEach(function(a){a[b](c,d,e)}):a[b](c,d,e)},f={init:function(){},start:function(a){return parseInt(a.node.textContent,10)},change:function(a,b){a.node.textContent=b},end:function(){}},g=function(a,b,c,d){this.name=a,this.prop=b,this.factor=c||1,this.divider=d||1};g.prototype={coordinate:function(a){return a[this.prop]},value:function(a,b){return this.factor*Math.floor((b-a)/this.divider)}};var h=function(a,b,c){return function(d){return new g(a,b,c,d)}},i=h("Horizontal","clientX"),j=h("Vertical","clientY",-1),k=function(){var b,c,d=function(){this.removeEventListener("mousemove",b,!1),c&&c.options.adapter.end(c)},e=function(e){if(e.target.scrubbingElement){e.preventDefault(),c=e.target.scrubbingElement;var f=c.options.adapter.start(c),g=function(a){return c.options.resolver.coordinate(a)},h=g(e);return b=function(a){if(1===a.which){var b=c.options.resolver.value(h,g(a));c.options.adapter.change(c,f+b,b)}else d()},a.addEventListener("mousemove",b,!1),a.addEventListener("mouseup",d,!1),!0}},f=function(){a.addEventListener("mousedown",e,!1),f=function(){}};return{init:function(){f()},remove:function(){}}}(),l=function(a){var b,c,d=function(){a.removeEventListener("touchmove",c,!1),b&&b.options.adapter.end(b)},e=function(d){if(1===d.targetTouches.length){var e=d.targetTouches[0];if(e.target.scrubbingElement){d.preventDefault(),b=e.target.scrubbingElement;var f=b.options.adapter.start(b),g=function(a){return b.options.resolver.coordinate(a)},h=g(e);c=function(a){if(1===a.targetTouches.length){a.preventDefault();var c=b.options.resolver.value(h,g(a.targetTouches[0]));b.options.adapter.change(b,f+c,c)}},a.addEventListener("touchmove",c,!1)}}},f=function(){a.addEventListener("touchcancel",d,!1),a.addEventListener("touchend",d,!1),f=function(){}};return{init:function(a){f(),a.node.addEventListener("touchstart",e,!1)},remove:function(){}}}(a,b),m=function(){return{init:function(a){a.node.addEventListener("mousewheel",function(b){b.preventDefault();var c=a.options.adapter.start(a);a.options.adapter.change(a,c-b.wheelDelta,b.wheelDelta)},!1)},remove:function(){}}}(a),n={driver:[l,k],resolver:i(),adapter:f},o=function(a,b){return this instanceof o?(this.node=a,this.options={},d(this.options,b,n,o.driver,"driver"),d(this.options,b,n,o.resolver,"resolver"),d(this.options,b,n,o.adapter,"adapter"),this.node.dataset.scrubOrientation=this.options.resolver.name,a.scrubbingElement=this,this.options.adapter.init(this),e(this.options.driver,"init",this),void 0):new o(b)};o.prototype={remove:function(){delete node.scrubbingElement,e(this.options.driver,"remove",this)}},o.driver={Mouse:k,MouseWheel:m,Touch:l},o.adapter={BasicNode:f},o.resolver={DefaultHorizontal:i(),DefaultVertical:j(),HorizontalProvider:i,VerticalProvider:j},a.Scrubbing=o}(window);

// Horizontal
new Scrubbing ( document.querySelector ( '#scrubbing-horizontal') )

// Horizontal / with mousewheel
new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-wheel')
               , { driver : [ Scrubbing.driver.Mouse,
                              Scrubbing.driver.MouseWheel,
                              Scrubbing.driver.Touch
                            ]});
 
// Vertical
new Scrubbing ( document.querySelector ( '#scrubbing-vertical')
             , { resolver : 'DefaultVertical' } ); 

// Vertical / Diffrent with friction
new Scrubbing ( document.querySelector ( '#scrubbing-vertical-friction')
             , { resolver : Scrubbing.resolver.VerticalProvider ( 50 ) } ); 
 

// Horizontal / Custom Values
// Here there is a Excel like letter iterator. 
var MyOwnAdapter = {
  
    _makeLetter : function ( letterCode ) {
      var letter = '';
      while ( letterCode >= 0 ){
        letter     = String.fromCharCode ( letterCode % 26 + 65 ) + letter;
        letterCode = parseInt ( letterCode / 26, 10 ) - 1; 
      }
      return letter;
    },
    
    init : function ( element ) {
      element.node.dataset.value =  parseInt ( element.node.textContent.charCodeAt(0), 10 ) - 65;
    },
  
    start : function ( element ){
      return parseInt ( element.node.dataset.value, 10 );
    }, 
    
    change : function ( element, value ) { 
      value = value > 0 ? value : 0;
      element.node.dataset.value = value;
      element.node.textContent = this._makeLetter ( value );
    },
    
    end : function () { }
};


new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-custom')
             , { adapter  : MyOwnAdapter 
               , resolver : Scrubbing.resolver.HorizontalProvider ( 30 ) });



var ArrayAdapter = function ( array ) {
  this.currentIndex = 0;
  this.data = array;
};

ArrayAdapter.prototype = {
  
  init : function ( element ) { 
     element.node.textContent = this.data[this.currentIndex];
  },
  
  start : function ( ){
    return this.currentIndex;
  }, 
  
  change : function ( element, value ) {
    this.currentIndex = Math.abs ( (this.data.length + value) % this.data.length );
    element.node.textContent = this.data[ this.currentIndex ];
  },
  
  end : function ( element ) { }
}


new Scrubbing ( document.querySelector ( '#scrubbing-horizontal-array')
             , { adapter  : new ArrayAdapter(["Test",  "Test1", "Test2"
                                             ,"Test3", "Test4", "Test5"
                                             ,"Test6"])
               , resolver : Scrubbing.resolver.HorizontalProvider ( 50 )});


var codeElemList = document.querySelectorAll('code'),
    codeElems = [].slice.call(codeElemList);

codeElems.forEach(function (elem){
  elem.setAttribute('class', 'language-javascript');
  Prism.highlightElement (elem);
});  


    

External CSS

  1. https://codepen.io/FWeinb/pen/71d48d3082f94719ee18e546e555b24b.css

External JavaScript

  1. https://codepen.io/FWeinb/pen/71d48d3082f94719ee18e546e555b24b.js