darsain / sly

JavaScript library for one-directional scrolling with item based navigation support.
http://darsa.in/sly
2.87k stars 497 forks source link

scrollBy works incorrect in Firefox #137

Closed AlexCSR closed 10 years ago

AlexCSR commented 10 years ago

When I use smart sliding with scrollBy=1 Chrome scrolls item by item well but Firefox catchs and scrolls two items at once. Then if I set scrollBy=2 Firefox scrolls four items.

You can try this even on the official demo page: http://darsa.in/sly/examples/vertical.html

Could you fix that please?

AlexCSR commented 10 years ago

I see that bug on any demo. Prev/next buttons works well, but mousewheel always makes double-scroll.

darsain commented 10 years ago

Doesn't happen for me. Are you per chance on Macbook and scrolling with touchpad? Or using a mouse with high precision scrolling? (doesn't make one scroll event per wheel notch, but fires tons of tons of them as you're turning the wheel)

What is your version of Firefox?

AlexCSR commented 10 years ago

I'm using Firefox 30.0 on Windows 8.1. I have a PC, not a notebook. I have old Razer Lachesis mouse. I can send you some screenshots with its settings if it'll make sense. But I don't think that mouse settings fires trouble because the script works well in other browsers.

darsain commented 10 years ago

Go here: http://jsfiddle.net/v2Jem/

Make some scrolls and paste here the output.

AlexCSR commented 10 years ago

In Firefox (6 as usual, 12 when scrolling fast): DOMMouseScroll wheelDelta: undefined detail: -12 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: -6 deltaY: undefined

In Chrome (always): wheelDelta: -120 detail: 0 deltaY: 200

I tested the demo on another computer (notebook HP Presario, Win7, with simple wireless mouse). In Firefox: 1) When I'm scrolling it slowly (one scroll per ~3 second) slider doesn't work. 2) When I'm doing ~2 equable scrolls per second it scrolls item by item but sometimes I need two mousewheels to scroll one item (it usually happens 2 times on 15-slides demo). 3) And it works pretty well when I'm scrolling too fast. That's the output (3 as usual, big values when I'm doing fast scroll): DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 2 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 5 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 6 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 17 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 2 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 8 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 11 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 2 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 3 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 9 deltaY: undefined DOMMouseScroll wheelDelta: undefined detail: 8 deltaY: undefined

At least in Chrome on notebook I see the same things as in Firefox on PC. When I'm scrolling slower than ~3 mousewheels per second nothing happens. If I do it faster (even if too fast) slides jumps like 2-4-6-8-9-11 etc. The output (always the same): mousewheel wheelDelta: 112 detail: 0 deltaY: -93.33333587646484

darsain commented 10 years ago

Yes, everything you are describing is an intended behavior.

In item based navigation, you don't scroll by pixels, but by items. That means Sly has to translate different types of scroll events into number of items to be scrolled. It also has to take into account mouses with high precision wheels, as well as touch pads. In both of these special cases, Sly has to concatenate several events into one item scroll, otherwise, due to high frequency nature of high precision events, you'd be scrolling by 100 items all the time. This is done by caching the deltas and firing 1 item scroll when normalized delta reaches 1. If you scroll very slowly, the old events will be discarded and you'll never reach one item scroll. On the other hand if you scroll fast, the deltas are accumulating more than usual, which'll result into delta higher than 1, which means scroll by more than one item.

In your output above, detail: 3 means scroll by 1 item, as 3 is the base detail number. detail: 12 means scroll by 4 items, because 12 / 3 = 4 (Sly assumes 4 events of fast scrolling has been already concatenated into one by a browser).

If there is a detail: 11, it is normalized to a delta 3.6666, so you scroll by 3 items, and 0.6666 is cached and added to the next item scroll, or discarded if the next event comes in more than 200 milliseconds from the last one.

This is the function that normalizes scrolling deltas:

function normalizeWheelDelta(event) {
    // event.deltaY needed only for compatibility with jQuery mousewheel plugin in FF & IE
    scrolling.curDelta = event.wheelDelta ? -event.wheelDelta / 120 : (event.detail || event.deltaY) / 3;
    if (!itemNav) {
        return scrolling.curDelta;
    }
    time = +new Date();
    if (scrolling.last < time - scrolling.resetTime) {
        scrolling.delta = 0;
    }
    scrolling.last = time;
    scrolling.delta += scrolling.curDelta;
    if (Math.abs(scrolling.delta) < 1) {
        scrolling.finalDelta = 0;
    } else {
        scrolling.finalDelta = Math.round(scrolling.delta / 1);
        scrolling.delta %= 1;
    }
    return scrolling.finalDelta;
}

Reset time is 200 milliseconds, so if your scrolls don't amount to a normalized delta >=1 on their own, and you are firing them more than 200 milliseconds apart, you'll never scroll one item.

darsain commented 10 years ago

There has been a scrolling overhaul where I dumped DOMMouseScroll event and reimplemented it in wheel with a fallback to mousewheel in IE8-. It works nicely, and this was mostly a question so I'm gonna close this issue.

If there is still a discrepancy between scrolling in different browsers that just can't be ignored, feel free to comment and I'll reopen this issue.