Home > Mobile >  Canceling the emission sequence with Observables RxJS
Canceling the emission sequence with Observables RxJS

Time:08-06

I'm creating a thread to control mouse directions (pixel by pixel) using javascript. Sometimes I need to stop the mouse movement and give it a new direction (a set of pixels). I would like to use Observables.

I would like to output the pixel sequences, for example: [(x0, x0), ..., (xN, yN), (x1, y1)]

If a new set of pixels is issued, the previous one will be cleaned.

I would like to know the best way to do this, which operators, etc.

CodePudding user response:

Assuming you are emitting a "sequence" as an array of "points", something like this should work:

type Point = [number, number];

const DELAY = 200;
const pixelSequence$ = new Subject<Point[]>();

const mousePoint$ = pixelSequence$.pipe(
  switchMap(sequence => timer(0, DELAY).pipe(
    map(i => sequence[i]),
    take(sequence.length),
  ))
);

mousePoint$.subscribe(
  ([x, y]) => setMousePosition(x, y)
);

Here we start with a Subject that will emit a "pixel sequence" (Point[]). We can define a new Observable that will emit individual points, then subscribe to that observable to set the cursor position:

mousePoint$.subscribe(
  ([x, y]) => setMousePosition(x, y)
);

The core of the functionality happens in the definition of mousePoint$. We define a new Observable that begins when pixelSequence$ emits a value. We then use switchMap and create an "inner observable" that emits the sequence items one at a time at with the specified DELAY inbetween.

  switchMap(sequence => timer(0, DELAY).pipe(
    map(i => sequence[i]),
    take(sequence.length),
  ))

If you aren't familiar with switchMap, it basically receives a emission as input, then subscribes to an "inner observable" for you, emitting its emissions. When switchMap receives a new emission, it will "switch" its inner source to a new observable, unsubscribing from its previous "inner observable".

So, to begin your mouse moving, simply call pixelSequence$.next() with an array of coorinates. If you need to use a different sequence (whether or not the current sequence has been fully processed), simply call pixelSequence$.next() again with the new sequence.

Here is a example on StackBlitz.

Operators used:

  • switchMap - subscribe to inner observable and emit its emissions
  • timer - emit sequential integers at the specified interval
  • map - transform each emission with the provided function
  • take - complete the observable when the specified number of emissions have been received
  • Related