0

So, in the following example from RxJS on GitHub, when is the mouse move observable 'activated', by which I mean, what triggers it to start sampling the mousemove event?

I thought the subscribe would mark the start of the sequences for all the observables in mousedrag, but that does not seem to be the case. Obviously, there are mousemove events before the mousedown, but these events are never used.

var dragTarget = document.getElementById('dragTarget');

// Get the three major events
var mouseup   = Rx.Observable.fromEvent(dragTarget, 'mouseup');
var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');

var mousedrag = mousedown.flatMap(function (md) {
    // calculate offsets when mouse down
    var startX = md.offsetX, startY = md.offsetY;

    // Calculate delta with mousemove until mouseup
    return mousemove.map(function (mm) {
        mm.preventDefault();

        return {
            left: mm.clientX - startX,
            top: mm.clientY - startY
        };
    }).takeUntil(mouseup);
});

// Update position
var subscription = mousedrag.subscribe(function (pos) {          
    dragTarget.style.top = pos.top + 'px';
    dragTarget.style.left = pos.left + 'px';
});

Any insight would be appreciated.

André Staltz
  • 13,304
  • 9
  • 48
  • 58
bnieland
  • 6,047
  • 4
  • 40
  • 66

1 Answers1

1

I'm a big fan of RxJS because of the answer to your question!

...when is the mouse move observable 'activated', by which I mean, what triggers it to start sampling the mousemove event?

The mouse move observable is "activated" (the real term is "subscribed to") at the moment that is needed and then disposed of the moment it is not! The exact location that the event binding occurs in the example you provided is after

return mousemove.map(function (mm) { ... })

is called (which isn't called until after mousedrag.subscribe is called).

If you look in the code for observable.map, you will see that the parent (mousemove in this case) is subscribed to and the function passed into map is called inside its onNext event.

If you dig deep down the bunny hole, you'll come across Observable.fromEvent which is the exact location where the event listening occurs, but for all intents and purposes, the subscribe method called in the observable.map function is where it is "activated".

Finally, the .takeUntil(mouseup) method that is called at the end of the .map chain is where everything gets cleaned up and disposed. The onNext for that observable will dispose of the previous subscription, which in the case of the example, would be the .map function aka the event listener. Once a mouseup event occurs, the subscription for mousemove is disposed of and "deactivated".

To test this, you can Set breakpoints at var subscription = ..., return mousemove.map and mm.preventDefault();, and they would be hit in this order:

  1. var subscription = ...
  2. Mouse down
  3. return mousemove.map
  4. mouse move
  5. mm.preventDefault();
  6. mouse up
  7. mouse move, no breaking

Let me know if that makes sense, or if you have any questions about what I posted. I can clarify anything that you still don't understand.

Good luck!

joe_coolish
  • 7,201
  • 13
  • 64
  • 111
  • Thank your answer. You answer certainly has clarified many questions I had. I am still confused about one thing you said. "Finally, the .takeUntil(mouseup) method that is called at the end of the .map chain is where everything gets cleaned up and disposed. The onNext for that observable will dispose of the previous subscription" The subscription does not seem to be disposed of when the takeUntil event fires, but it does seem to restart the composition (Which is fine with me). Can you expand on this process? – bnieland Aug 10 '14 at 13:23
  • I have another question with a good fiddle attached that you might also be interested in and/or be able to help with: http://stackoverflow.com/questions/24598299/how-to-cancel-a-composed-rxjs-observable/24600950#24600950 – bnieland Aug 10 '14 at 13:27