Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJs How do deal with document events

Started using RxJs. Can't find a way around this problem. I have a draggable control:

startDrag = rx.Observable.fromEvent(myElem,'mousedown')

now, because the control is too small mousemove and mouseup events should be at document level (otherwise it won't stop dragging unless cursor exactly on the element)

endDrag = rx.Observable.fromEvent document,'mouseup'

position = startDrag.flatMap ->
   rx.Observable.fromEvent document,'mousemove'
   .map (x)-> x.clientX
   .takeUntil endDrag

now how do I "catch" the right moment when is not being dragged anymore (mouseup). you see the problem with subscribing to endDrag? It will fire every time clicked anywhere, and not just myElem How do I check all 3 properties at once? It should take only those document.mouseups that happened exactly after startDrag and position

Upd: I mean the problem is not with moving the element. That part is easy - subscribe to position, change element's css. My problem is - I need to detect the moment of mouseup and know the exact element that's been dragged (there are multiple elements on the page). How to do that I have no idea.

like image 764
iLemming Avatar asked Feb 12 '15 12:02

iLemming


1 Answers

I have adapted the drag and drop example provided at the RxJS repo to behave as you need.

Notable changes:

  • mouseUp listens at document.

  • The targeted element is added to the return from select.

  • Drag movements are handled inside of map and map returns the element that was targeted in the mouseDown event.

  • Call last after takeUntil(mouseUp) so subscribe will only be reached when the drag process ends (once per drag).

Working example:

function main() {
  var dragTarget = document.getElementById('dragTarget');

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


  var mousedrag = mousedown.selectMany(function(md) {

    // calculate offsets when mouse down
    var startX = md.offsetX;
    var startY = md.offsetY;

    // Calculate delta with mousemove until mouseup
    return mousemove.select(function(mm) {
      if (mm.preventDefault) mm.preventDefault();
      else event.returnValue = false;

      return {
        // Include the targeted element
        elem: mm.target,
        pos: {
          left: mm.clientX - startX,
          top: mm.clientY - startY
        }
      };
    })
    .map(function(data) {
      // Update position
      dragTarget.style.top = data.pos.top + 'px';
      dragTarget.style.left = data.pos.left + 'px';

      // Just return the element
      return data.elem;
    })
    .takeUntil(mouseup)
    .last();
  });


  // Here we receive the element when the drag is finished
  subscription = mousedrag.subscribe(function(elem) {
    alert('Drag ended on #' + elem.id);
  });
}
main();
#dragTarget {
  position: absolute;
  width: 20px;
  height: 20px;
  background: #0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
<div id="dragTarget"></div>
like image 195
Jon Surrell Avatar answered Sep 18 '22 10:09

Jon Surrell