First, we get a handle on the scroll stream with the use of fromEvent observable creator.

fromEvent Creates an observable sequence by adding an event listener to the matching DOMElement

To get better performance, we throttle the event stream with the use of the throttleTime operator. We keep the throttle value low as we don’t want to make the showing and hiding of the header to feel unresponsive.

throttleTime Returns an Observable that emits only the first item emitted by the source Observable during sequential time windows of a specified duration.

Next, we map the window object to the pageYOffset , which returns the number of pixels the document is currently scrolled along the vertical axis.

Since we’re interested in the direction of the scrolling, we must compare the subsequent changes to the pageYOffset as the user scrolls.

To achieve this, we group the values emitted by the scroll stream in pairs with the use of the pairwise operator.

pairwise Triggers on the second and subsequent triggerings of the input observable. The Nth triggering of the input observable passes the arguments from the N-1th and Nth triggering as a pair.

Next, we compare the pixel values in each pair. If the second value is lower than the first, the user is scrolling up. Otherwise, he is scrolling down.

Notice that there are a lot of repeated values being emitted. Since we are only interested in the changes of the direction, we can remove the repeated events with the use of the distinctUntilChanged operator.

distinctUntilChanged Returns an observable sequence that contains only distinct contiguous elements

Finally, we create two streams: scrollUp$ and scrollDown$ with the use of the filter operator. We also apply the share operator to the scroll$ stream, to avoid creating multiple subscriptions.