Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a single event emit multiple items in RxJS?

Tags:

rxjs

I'm binding together SVG graphics and mouse/touch events, using RxJS.

One of the challenges is that on iOS, a single touchstart event can carry multiple touch data. When it's just one, I can trivially use select and convert each TouchEvent to an observable of coordinates (i.e. each touch start initiates a new drag). But how can I add 2 or 3 entries to the observable, from just the single event?

Not sure if flatMap is the thing. Maybe selectMany is? I've read the manuals but they are ... a bit entangled and full of streamy language.

The lines in question are these. If you are interested in making interactive SVG graphics in a browser easier to program for, welcome to help with the project!

like image 435
akauppi Avatar asked Jan 06 '16 17:01

akauppi


2 Answers

selectMany is the same as flatMap. RxJS provides some examples, also for Drag'n'Drop, you can find it here.

If this doesn't fit your needs, you can use a Rx.Subject to send notifications around, e.g.

var oneSubject = new Rx.Subject();
var otherSubject = new Rx.Subject();
someObservable.subscribe(function(x) {
    oneSubject.onNext('hello');
    otherSubject.onNext(42);
});

// subscribe to oneSubject or otehrSubject

EDIT If you mean with "one event to multiple items" that you get an x and want to send n times x, then you can also use repeat, e.g. n = 10

someObservable.flatMap(function(x) { return Rx.Observable.repeat(x, 10); });
like image 149
Martin Seeler Avatar answered Jan 04 '23 00:01

Martin Seeler


The .selectMany is really rather trivial to use, it seems.

Whereas for select one would convert an input value to an output (emitted) value, for .selectMany one returns an array or observable (both work) of the 0..n values one wishes to emit. That's it. :)

My code ended up being like this:

return range( 0, ev.changedTouches.length ).map( function (i) {
  return touchDragObs( ev, i );
} );

The range is a helper function to create an 0..n-1 seed array:

// JavaScript does not have an Array for range constructor.
//
function range( start, count ) {    // (Int,Int) -> Array of Int
  var arr = [];
  for (var i=0; i<count; i++ ) {
    arr[i]= start+i;
  }
  return arr;
}

Another option would be this (both work):

return Rx.Observable
        
  .range(0,ev.changedTouches.length)   // (start, count)
  .select( function (i) {
    return touchDragObs( ev, i );
        
});
        

If anyone knows the performance indications of the above options, I'd like to know.

like image 33
akauppi Avatar answered Jan 04 '23 01:01

akauppi