Reputation: 6516
I am using rxjs to handle some complex mouse gestures.
One of these gesures is to "shake" the mouse (left to right, right to left, ...) several times during a drag operation.
As I do not know whether the user will start by moving the the left or right, I am using 'race()' to accept whichever starts first.
My problem is that when the first "shake" observer completes, the second has already completed.
I have made a simplified example here, on jsbin (http://jsbin.com/wuzodog/3/edit?html,js,output.)
(I am using negative numbers as "mouse left" and positive as "mouse right" in this simplified example.)
The core of the issue is demonstrated here...
const subMouseMove = new Rx.Subject<number>();
const obLeft = subMouseMove.filter(m => m < 0);
const obRight = subMouseMove.filter(m => m >= 0);
const get_obLeftUntilRight = () => obLeft.takeUntil(obRight);
const get_obRightUntilLeft = () => obRight.takeUntil(obLeft);
const get_obShake = () => Rx.Observable.race(get_obLeftUntilRight(), get_obRightUntilLeft());
const obDragShakeAndDrop = Rx.Observable.concat(
get_obShake(),
get_obShake(),
);
//sending the following values to subMouseMove
[-1, -2, 3, 4, -5].forEach((v, i, a) => setTimeout(() => subMouseMove.next(v), i * 10));
The problem is that both instances of get_obShake() are being completed at the same time.
The results I am getting from the jsbin are:
I would expect my results to be:
When I modify the example (http://jsbin.com/wuzodog/4/edit?html,js,output), calling the "shake left/right" and the "shake right/left" directly, bypassing "race()", I get the 'expected' output.
Can anyone explain why the second shake is completing early in the first example?
Upvotes: 0
Views: 889
Reputation: 14717
It's tricky, but the answer is more rational then you think. The issue is that Race also accepts completion as the first winning Observable.
const get_obLeftUntilRight = () => obLeft.takeUntil(obRight);
const get_obRightUntilLeft = () => obRight.takeUntil(obLeft);
When we look at these two Observables, if there is 'left' event, the first will emit and the second will complete immediately. If we get a 'right' event the first will complete immediately and the second...
This is probably what you want:
const get_obLeftUntilRight = () => obLeft.take(1).concat(obLeft.takeUntil(obRight));
const get_obRightUntilLeft = () => obRight.take(1).concat(obRight.takeUntil(obLeft));
Upvotes: 2
Reputation: 23533
The difference between the two jsBin outputs is that
** NEXT: get_obShake2 = 4
is missing from the first, because race
has eliminated it.
So, it's not that the second shake is completing early, it's just a shorter sequence.
Add some timestamp()
to check it out.
I have to say, I don't get the feeling of this code doing what you intend, but that could well be my lack of understanding.
Upvotes: -1