Search code examples
javascriptrxjsbacon.js

How to filter out the top most click event from a list of click event streams?


I have a stack of cards with bounds { x, y, w, h } stacked on top of each other with some offset y value.

I am trying to implement click events on this cards. So I have a click event stream on document as such:

let starts = fromEvent(document, 'mousedown'),
     ends = fromEvent(document, 'mouseup');

starts = starts.map(e => {
  let epos = eventPosition(e);
  return {
    start: epos,
    epos
  };
});

ends = ends.map(e => {
  return {
    epos: eventPosition(e)
  };
});

let clicks = starts.flatMap(startE => {
  return ends.first()
             .takeUntil(later(600));
});

function Card(n) {

  // inHitBounds returns true when event position is within the cards bounds.
  let inHitBounds = _ => hitTest(..._.epos, container.bounds());
  let insertN = _ => ({ ..._, n });

  // returns a stream which emits a card click event whenever it is in bounds of this card.
  this.clicks = clicks.filter(inHitBounds).map(insertN);
}

function CardStack(stack) {

  let dCards = stack.map(n => new Card(n));

  // returns a stream which emits a card click event with the upper most card that is clicked.
  this.clicks = ???

  // I tried this but it failed:
  this.clicks = dCards
                   .map(_ => _.clicks)
                   .reduce((acc, _) => acc.merge(_), Bacon.never)
                   .first();
}

Solution

  • there's actually a method Bacon.groupSimultaneous which lets you group "simultaneous" events from multiple sources. I wrote an example: https://codesandbox.io/s/groupsimultaneous-example-cdthp

    So you can group events from your cards and from a group of events select the one which represents the topmost card.

    Just realized that this method is excluded from the API docs at https://baconjs.github.io/api3/globals.html

    Otherwise you might rethink a bit and create a stream that listens to clicks and then, based on the dCards array, picks the topmost card which intersects with the click pos.