Skip to content

Instantly share code, notes, and snippets.

@kosich
Last active March 5, 2019 15:23
Show Gist options
  • Select an option

  • Save kosich/fa4eb1c0ed0cea4252be282ef8028a7f to your computer and use it in GitHub Desktop.

Select an option

Save kosich/fa4eb1c0ed0cea4252be282ef8028a7f to your computer and use it in GitHub Desktop.
Pausing observable on mouse hover with event spacing example
const { rxObserver } = require('api/v0.3');
const { of, timer, fromEvent, merge, empty, interval, Subject, forkJoin } = require('rxjs');
const { startWith, switchMap, distinctUntilChanged, map, mapTo, take, tap, concatMap, ignoreElements, multicast, shareReplay } = require('rxjs/operators');
const mouse$ = new Subject();
const TIMEOUT = 50;
const notifications$ = new Subject();
merge(
timer(20, 170),
timer(130, 280)
)
.take(7)
.map(v => 'M:' + v)
.subscribe(notifications$);
// we need to remember what was the latest mouse position
// otherwise it will be reset when new msg comes in
const memMouse$ = mouse$
.startWith(false)
.pipe(shareReplay(1));
let currentMsgIndex = -1;
const display$ = notifications$.pipe(
// store current msg index
map((msg,i) => {
currentMsgIndex = i;
return msg;
}),
concatMap((msg, i) => {
// we listen to events from the mouse
// starting with "mouse away" state (false)
return memMouse$.pipe(
// if mouse pos changed -- reeval timeout
switchMap(value => {
// do nothing on mouse in
if (value) {
return empty();
}
// until next msg comes in -- we're tracking mouse in/out
let nextMsgAwait$;
if (i == currentMsgIndex) {
nextMsgAwait$ = notifications$.take(1);
} else {
nextMsgAwait$ = of(void 0);
}
// if mouse is away -- wait for
// - timer for TIMEOUT
// - wait till new msg arrives
// until then -- user can mouse in/out
// to delay the next msg display
return forkJoin(
timer(TIMEOUT)
, nextMsgAwait$
);
}),
take(1),
// DEBUG {{{
map(_=>Date.now()),
tap(rxObserver('Mouse minding gap')),
// }}}
// basically ignoring everything, we need only the delay here
ignoreElements(),
// pushing message to the start of the stream
// here
// ...............(timeout)|
// becomes
// (msg)...................|
startWith(msg)
);
})
);
setTimeout(()=>{
mouse$.next(true);
}, 150);
setTimeout(()=>{
mouse$.next(false);
}, 250);
// pushing first msg directly to the display
display$
.skip(1)
.merge(notifications$.take(1))
.map(v=>Date.now())
.subscribe(rxObserver('Display stream'));
notifications$
.subscribe(rxObserver('Notifications'));
mouse$
.subscribe(rxObserver('mouse'));
@kosich
Copy link
Author

kosich commented Mar 5, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment