Wheel-indicator - touchstart emulation plugin when working with trackpads

    Inertial input devices are devices such as touchscreens, trackpads, magic mouse, etc., In their work, trackpads and magic mouse resemble the touchscreens of mobile devices, i.e. continue to generate mouse wheel events after the user has finished the gesture. But unlike these, we do not have a native touchstart event. All we have is a wheel event object . Touchstart is often necessary in order to comfortably implement the work of the so-called fullpage-sites, where when scrolling there is a transition between screens. An example of such a site is alfabank.. It also has the problem of scrolling two screens in a row when using a magic mouse or trackpad (especially on macbooks). A rather weak gesture of scrolling down scrolls to the second, and then immediately to the third screen. To get to the second screen, you have to use a scrollbar. This is the kind of problem we tried to solve using only the wheel event object .

    So how do you implement touchstart?
    Let's start from the very simple and we will move on increasing. The simplest implementation of touchstart:
    0. Silence.
    1. The wheel event is triggered. This is our touchstart
    2. Suppose that between events there can be no more than 200ms (actually from 10 to 30ms), therefore, just 200ms after the last event, we again generate touchstart when new event objects appear.

    Already not bad, two pages will not be scrolled in one movement. But there is a significant problem: an attempt to start a new iteration of scrolling to the end of the current one will only lengthen the current one.

    To solve this problem, it is necessary to understand the moment when the user made a new gesture before the end of the previous iteration.
    Having analyzed the wheel event object, we immediately noticed the deltaY field. It reflects the strength with which the device is currently operating.
    If you display the deltaY values ​​on the chart, the gesture will look something like this:

    And this is what we need to catch.

    Thus, the task is to compare the previous value of deltaY with the current one. And if it is larger, then the user has started a new conscious movement, that is, a new touchstart has occurred.

    Everything seems to be fine, the interface has become more responsive, it has become possible to make any number of gestures in a row, without waiting for the previous iteration to finish working. But in practice, the algorithm crashed: touchstart was often generated more often than necessary. Sometimes 2-3 times per iteration. Why did this happen? An analysis of the numerical series deltaY from one iteration showed that sometimes despite the decline in iteration (i.e., the slowdown of inertia expressed in ever decreasing deltaY values ​​in each subsequent wheel event), sometimes the current deltaY may be equal to or greater than the previous one. And sometimes this happened after a time:
    21, 17, 15, 18 , 12, 14 , 10, 7 ...

    or two consecutive increases of
    21, 17, 15, 18 , 19 , 14, 10 ...

    Numerous experiments have shown that there are practically no more than three such situations in a row for both cases. We make corrections to the algorithm: now touchstart is generated only if the current deltaY is greater than the previous and the next deltaY is greater than the current. Now everything is working fine, and there are no more obvious problems.

    Based on this approach, we wrote the wheel-indicator plugin . Other factors are also used in the analysis, but there is no point in describing them all within the framework of this article.

    Ordinary mice

    The plugin can also be used as an easy replacement for the well - known jquery-mousewheel in cases where you only need to cross-browser determine the direction of the wheel. If the user's mouse triggers a lot of events, the plugin will also normalize this. Sometimes it is useful, for example, to scroll with a wheel such a carousel is not very comfortable. In addition, non-blocking interfaces can be implemented on the basis of the plugin. For example, here you can scroll in the process of animation in any direction, and the number of transitions will be equal to the number of user gestures.

    Testing
    Because this algorithm is not final and will probably improve, I wanted to be able to test it. Essentially, the plugin receives a number series from deltaY at the input and analyzes it. That means nodejs and travis-ci.org are enough to write tests to test commits.
    In order to be able to test the plugin in nodejs, it is necessary that it can export itself in the commonjs format.
    To do this, add a check and export the constructor:
    if (typeof exports === 'object') {
        module.exports = WheelIndicator;
    }
    

    The input for the plugin comes through the event object after creating the handler using addEventListener. Thus, in the tests we need to "lock up" this method:
    global.document = {
        addEventListener: function(type, handler){
            currentDeltaArr.forEach(function(delta){
                handler({
                    deltaY: delta
                });
            });
        }
    };
    

    where delta is an array of a test number series from deltaY. To conveniently obtain such series from various devices and OS, we made a test stand .

    That's all, now all that’s left to do is to re-establish the plug-in, create an instance and compare the data received from the plug-in with the reference data.

    Example input for test:
    down: {
        moves: [ 'down' ],
        delta: [1,4,12,32,55,69,154,156,158,148,137,130,122,116,111,108,103,97,93,88,84,80,74,71,65,61,57,54,50,46,42,39,36,33,31,27,25,23,21,18,17,15,14,13,12,11,9,8,8,7,6,6,14,4,4,3,3,3,2,2,4,1,2,1,1,1,1,1,1,1,1,1,1],
        device: 'Mac OSX notebook trackpad'
    }
    


    You can read about the connection, documentation and download the plugin on the repository page .

    Also popular now: