Skip to content

Instantly share code, notes, and snippets.

@jdeagle
Forked from BASICjfisher/gist:4e802658cc61c104681d
Last active August 29, 2015 14:14
Show Gist options
  • Save jdeagle/17f3c80a30152ca63dd4 to your computer and use it in GitHub Desktop.
Save jdeagle/17f3c80a30152ca63dd4 to your computer and use it in GitHub Desktop.

Revisions

  1. @jacobfisherr jacobfisherr renamed this gist Feb 4, 2015. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gistfile1.txt → gistfile1.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,4 @@


    var VirtualScroll = function() {

    var vs = {};
  2. @jacobfisherr jacobfisherr created this gist Feb 4, 2015.
    179 changes: 179 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,179 @@


    var VirtualScroll = function() {

    var vs = {};

    var numListeners, listeners = [], initialized = false;

    var touchStartX, touchStartY;

    // [ These settings can be customized with the options() function below ]
    // Mutiply the touch action by two making the scroll a bit faster than finger movement
    var touchMult = 2;
    // Firefox on Windows needs a boost, since scrolling is very slow
    var firefoxMult = 15;
    // How many pixels to move with each key press
    var keyStep = 500;
    // General multiplier for all mousehweel including FF
    var mouseMult = 1;

    var bodyTouchAction;

    var hasWheelEvent = 'onwheel' in document;
    var hasMouseWheelEvent = 'onmousewheel' in document;
    var hasTouch = 'ontouchstart' in document;
    var hasTouchWin = navigator.msMaxTouchPoints && navigator.msMaxTouchPoints > 1;
    var hasPointer = !!window.navigator.msPointerEnabled;
    var hasKeyDown = 'onkeydown' in document;

    var isFirefox = navigator.userAgent.indexOf('Firefox') > -1;

    var event = {
    y: 0,
    x: 0,
    deltaX: 0,
    deltaY: 0,
    originalEvent: null
    };

    vs.on = function(f) {
    if(!initialized) initListeners();
    listeners.push(f);
    numListeners = listeners.length;
    }

    vs.options = function(opt) {
    keyStep = opt.keyStep || 120;
    firefoxMult = opt.firefoxMult || 15;
    touchMult = opt.touchMult || 2;
    mouseMult = opt.mouseMult || 1;
    }

    vs.off = function(f) {
    listeners.splice(f, 1);
    numListeners = listeners.length;
    if(numListeners <= 0) destroyListeners();
    }

    var notify = function(e) {
    event.x += event.deltaX;
    event.y += event.deltaY;
    event.originalEvent = e;

    for(var i = 0; i < numListeners; i++) {
    listeners[i](event);
    }
    }

    var onWheel = function(e) {
    // In Chrome and in Firefox (at least the new one)
    event.deltaX = e.wheelDeltaX || e.deltaX * -1;
    event.deltaY = e.wheelDeltaY || e.deltaY * -1;

    // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad
    // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes
    if(isFirefox && e.deltaMode == 1) {
    event.deltaX *= firefoxMult;
    event.deltaY *= firefoxMult;
    }

    event.deltaX *= mouseMult;
    event.deltaY *= mouseMult;

    notify(e);
    }

    var onMouseWheel = function(e) {
    // In Safari, IE and in Chrome if 'wheel' isn't defined
    event.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0;
    event.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta;

    notify(e);
    }

    var onTouchStart = function(e) {
    var t = (e.targetTouches) ? e.targetTouches[0] : e;
    touchStartX = t.pageX;
    touchStartY = t.pageY;
    }

    var onTouchMove = function(e) {
    // e.preventDefault(); // < This needs to be managed externally
    var t = (e.targetTouches) ? e.targetTouches[0] : e;

    event.deltaX = (t.pageX - touchStartX) * touchMult;
    event.deltaY = (t.pageY - touchStartY) * touchMult;

    touchStartX = t.pageX;
    touchStartY = t.pageY;

    notify(e);
    }

    var onKeyDown = function(e) {
    // 37 left arrow, 38 up arrow, 39 right arrow, 40 down arrow
    event.deltaX = event.deltaY = 0;
    switch(e.keyCode) {
    case 37:
    event.deltaX = -keyStep;
    break;
    case 39:
    event.deltaX = keyStep;
    break;
    case 38:
    event.deltaY = keyStep;
    break;
    case 40:
    event.deltaY = -keyStep;
    break;
    }

    notify(e);
    }

    var initListeners = function() {
    if(hasWheelEvent) document.addEventListener("wheel", onWheel);
    if(hasMouseWheelEvent) document.addEventListener("mousewheel", onMouseWheel);

    if(hasTouch) {
    document.addEventListener("touchstart", onTouchStart);
    document.addEventListener("touchmove", onTouchMove);
    }

    if(hasPointer && hasTouchWin) {
    bodyTouchAction = document.body.style.msTouchAction;
    document.body.style.msTouchAction = "none";
    document.addEventListener("MSPointerDown", onTouchStart, true);
    document.addEventListener("MSPointerMove", onTouchMove, true);
    }

    if(hasKeyDown) document.addEventListener("keydown", onKeyDown);

    initialized = true;
    }

    var destroyListeners = function() {
    if(hasWheelEvent) document.removeEventListener("wheel", onWheel);
    if(hasMouseWheelEvent) document.removeEventListener("mousewheel", onMouseWheel);

    if(hasTouch) {
    document.removeEventListener("touchstart", onTouchStart);
    document.removeEventListener("touchmove", onTouchMove);
    }

    if(hasPointer && hasTouchWin) {
    document.body.style.msTouchAction = bodyTouchAction;
    document.removeEventListener("MSPointerDown", onTouchStart, true);
    document.removeEventListener("MSPointerMove", onTouchMove, true);
    }

    if(hasKeyDown) document.removeEventListener("keydown", onKeyDown);

    initialized = false;
    }

    return vs;
    };

    module.exports = VirtualScroll;