Skip to content

Instantly share code, notes, and snippets.

@hrmshandy
Forked from akella/facebook-normalize-wheel.js
Created December 6, 2018 05:54
Show Gist options
  • Save hrmshandy/2ac6675dbe954b7234a28b62853df22f to your computer and use it in GitHub Desktop.
Save hrmshandy/2ac6675dbe954b7234a28b62853df22f to your computer and use it in GitHub Desktop.

Revisions

  1. @akella akella created this gist Nov 25, 2017.
    181 changes: 181 additions & 0 deletions facebook-normalize-wheel.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,181 @@
    /**
    * Copyright (c) 2015, Facebook, Inc.
    * All rights reserved.
    *
    * This source code is licensed under the BSD-style license found in the
    * LICENSE file in the root directory of this source tree. An additional grant
    * of patent rights can be found in the PATENTS file in the same directory.
    *
    * @providesModule normalizeWheel
    * @typechecks
    */

    'use strict';

    var UserAgent_DEPRECATED = require('UserAgent_DEPRECATED');

    var isEventSupported = require('isEventSupported');


    // Reasonable defaults
    var PIXEL_STEP = 10;
    var LINE_HEIGHT = 40;
    var PAGE_HEIGHT = 800;

    /**
    * Mouse wheel (and 2-finger trackpad) support on the web sucks. It is
    * complicated, thus this doc is long and (hopefully) detailed enough to answer
    * your questions.
    *
    * If you need to react to the mouse wheel in a predictable way, this code is
    * like your bestest friend. * hugs *
    *
    * As of today, there are 4 DOM event types you can listen to:
    *
    * 'wheel' -- Chrome(31+), FF(17+), IE(9+)
    * 'mousewheel' -- Chrome, IE(6+), Opera, Safari
    * 'MozMousePixelScroll' -- FF(3.5 only!) (2010-2013) -- don't bother!
    * 'DOMMouseScroll' -- FF(0.9.7+) since 2003
    *
    * So what to do? The is the best:
    *
    * normalizeWheel.getEventType();
    *
    * In your event callback, use this code to get sane interpretation of the
    * deltas. This code will return an object with properties:
    *
    * spinX -- normalized spin speed (use for zoom) - x plane
    * spinY -- " - y plane
    * pixelX -- normalized distance (to pixels) - x plane
    * pixelY -- " - y plane
    *
    * Wheel values are provided by the browser assuming you are using the wheel to
    * scroll a web page by a number of lines or pixels (or pages). Values can vary
    * significantly on different platforms and browsers, forgetting that you can
    * scroll at different speeds. Some devices (like trackpads) emit more events
    * at smaller increments with fine granularity, and some emit massive jumps with
    * linear speed or acceleration.
    *
    * This code does its best to normalize the deltas for you:
    *
    * - spin is trying to normalize how far the wheel was spun (or trackpad
    * dragged). This is super useful for zoom support where you want to
    * throw away the chunky scroll steps on the PC and make those equal to
    * the slow and smooth tiny steps on the Mac. Key data: This code tries to
    * resolve a single slow step on a wheel to 1.
    *
    * - pixel is normalizing the desired scroll delta in pixel units. You'll
    * get the crazy differences between browsers, but at least it'll be in
    * pixels!
    *
    * - positive value indicates scrolling DOWN/RIGHT, negative UP/LEFT. This
    * should translate to positive value zooming IN, negative zooming OUT.
    * This matches the newer 'wheel' event.
    *
    * Why are there spinX, spinY (or pixels)?
    *
    * - spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn
    * with a mouse. It results in side-scrolling in the browser by default.
    *
    * - spinY is what you expect -- it's the classic axis of a mouse wheel.
    *
    * - I dropped spinZ/pixelZ. It is supported by the DOM 3 'wheel' event and
    * probably is by browsers in conjunction with fancy 3D controllers .. but
    * you know.
    *
    * Implementation info:
    *
    * Examples of 'wheel' event if you scroll slowly (down) by one step with an
    * average mouse:
    *
    * OS X + Chrome (mouse) - 4 pixel delta (wheelDelta -120)
    * OS X + Safari (mouse) - N/A pixel delta (wheelDelta -12)
    * OS X + Firefox (mouse) - 0.1 line delta (wheelDelta N/A)
    * Win8 + Chrome (mouse) - 100 pixel delta (wheelDelta -120)
    * Win8 + Firefox (mouse) - 3 line delta (wheelDelta -120)
    *
    * On the trackpad:
    *
    * OS X + Chrome (trackpad) - 2 pixel delta (wheelDelta -6)
    * OS X + Firefox (trackpad) - 1 pixel delta (wheelDelta N/A)
    *
    * On other/older browsers.. it's more complicated as there can be multiple and
    * also missing delta values.
    *
    * The 'wheel' event is more standard:
    *
    * http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
    *
    * The basics is that it includes a unit, deltaMode (pixels, lines, pages), and
    * deltaX, deltaY and deltaZ. Some browsers provide other values to maintain
    * backward compatibility with older events. Those other values help us
    * better normalize spin speed. Example of what the browsers provide:
    *
    * | event.wheelDelta | event.detail
    * ------------------+------------------+--------------
    * Safari v5/OS X | -120 | 0
    * Safari v5/Win7 | -120 | 0
    * Chrome v17/OS X | -120 | 0
    * Chrome v17/Win7 | -120 | 0
    * IE9/Win7 | -120 | undefined
    * Firefox v4/OS X | undefined | 1
    * Firefox v4/Win7 | undefined | 3
    *
    */
    function normalizeWheel(/*object*/ event) /*object*/ {
    var sX = 0, sY = 0, // spinX, spinY
    pX = 0, pY = 0; // pixelX, pixelY

    // Legacy
    if ('detail' in event) { sY = event.detail; }
    if ('wheelDelta' in event) { sY = -event.wheelDelta / 120; }
    if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120; }
    if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120; }

    // side scrolling on FF with DOMMouseScroll
    if ( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
    sX = sY;
    sY = 0;
    }

    pX = sX * PIXEL_STEP;
    pY = sY * PIXEL_STEP;

    if ('deltaY' in event) { pY = event.deltaY; }
    if ('deltaX' in event) { pX = event.deltaX; }

    if ((pX || pY) && event.deltaMode) {
    if (event.deltaMode == 1) { // delta in LINE units
    pX *= LINE_HEIGHT;
    pY *= LINE_HEIGHT;
    } else { // delta in PAGE units
    pX *= PAGE_HEIGHT;
    pY *= PAGE_HEIGHT;
    }
    }

    // Fall-back if spin cannot be determined
    if (pX && !sX) { sX = (pX < 1) ? -1 : 1; }
    if (pY && !sY) { sY = (pY < 1) ? -1 : 1; }

    return { spinX : sX,
    spinY : sY,
    pixelX : pX,
    pixelY : pY };
    }


    /**
    * The best combination if you prefer spinX + spinY normalization. It favors
    * the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with
    * 'wheel' event, making spin speed determination impossible.
    */
    normalizeWheel.getEventType = function() /*string*/ {
    return (UserAgent_DEPRECATED.firefox())
    ? 'DOMMouseScroll'
    : (isEventSupported('wheel'))
    ? 'wheel'
    : 'mousewheel';
    };

    module.exports = normalizeWheel;