Issue
I'm rather new to RXJS. What I want to achieve is to drag an HtmlElement when the user pushes the space (or any other) key and drags the element with the mouse.
So the start of the dragging is triggered by either SPACE-down_LeftClick or LeftClick_SPACE-down. Both are accepted to ease the usage. The end of the dragging is triggered by either releasing the SPACE key (keyup event) or the mouse click (mouseup event), whichever happens first.
The implementation idea was to have one 'dragstart' observable and one 'dragend' observable, to which I can subscribe to. I have 4 observables corresponding to the events, filtered on the specific key (space) and mouse button (left button) to start with:
spaceDown$ = fromEvent<KeyboardEvent>(document, "keydown").pipe( filter(key => key.code === 'Space'))
spaceUp$ = fromEvent<KeyboardEvent>(document, "keyup").pipe( filter( key => key.code === 'Space'))
mouseDown$ = fromEvent<MouseEvent>(document, "mousedown").pipe( filter( mouse => mouse.button == 0))
mouseUp$ = fromEvent<MouseEvent>(document, "mouseup").pipe( filter( mouse => mouse.button == 0))
What I'm struggling with is how to implement the desired behaviour in RXJS. I've tried with 'combineLatest', 'withLatestFrom', 'merge' different streams, but none of them works as I wish.
Any idea on how to solve this?
Solution
I would map the source observables to a bool value, where true would stand for pressed. Then create combined observables for keyboard and mouse. And then again combine those two streams. If both values are true there, it stands for a drag start event, otherwise it's drag end.
const spaceDown$ = fromEvent<KeyboardEvent>(document, 'keydown').pipe(
filter((key) => key.code === 'Space'),
map(() => true)
);
const spaceUp$ = fromEvent<KeyboardEvent>(document, 'keyup').pipe(
filter((key) => key.code === 'Space'),
map(() => false)
);
const mouseDown$ = fromEvent<MouseEvent>(document, 'mousedown').pipe(
filter((mouse) => mouse.button == 0),
map(() => true)
);
const mouseUp$ = fromEvent<MouseEvent>(document, 'mouseup').pipe(
filter((mouse) => mouse.button == 0),
map(() => false)
);
const key$ = merge(spaceDown$, spaceUp$).pipe(startWith(false));
const mouse$ = merge(mouseDown$, mouseUp$).pipe(startWith(false));
const combined$ = combineLatest([
key$,
mouse$,
]).pipe(
map(([key, mouse]) => key && mouse),
distinctUntilChanged(),
);
combined$.subscribe((res) => console.log('combined$', res));
// If different streams are required for dragstart and dragend:
const [dragStart$, dragEnd$] = partition(combined$, (val) => val);
dragStart$.subscribe(() => console.log('dragStart$'));
dragEnd$.subscribe(() => console.log('dragEnd$'));
Answered By - Bastian Bräu
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.