Search code examples
rxjskefir.js

Kefir.js drag example - drag end


I've been trying to factor a drag end stream / observeble into the Kefir drag div example but am not getting anywhere. Firing an event after a combination of mousedown, mousemove and mouseup would seem to make sense, but I just can't find a way to make it work. Any ideas?


Solution

  • This ended up working out well for me:

    var dragTarget = document.querySelector('#draggable');
    
    var mouseDowns = Kefir.fromEvents(dragTarget, 'mousedown');
    var mouseMoves = Kefir.fromEvents(document, 'mousemove');
    
    
    var moves = mouseDowns.flatMap(function(downEvent) {
      var mouseUp = Kefir.fromEvents(dragTarget, 'mouseup').take(1).onEnd(function(){
        alert('done dragging');
      });
      return mouseMoves.takeUntilBy(mouseUp)
        .diff(eventsPositionDiff, downEvent);
    });
    

    // Pure functions
    
    function eventsPositionDiff(prevEvent, nextEvent) {
      return {
        x: nextEvent.clientX - prevEvent.clientX,
        y: nextEvent.clientY - prevEvent.clientY
      };
    }
    
    function applyMove(currentPosition, move) {
      return {
        x: currentPosition.x + move.x,
        y: currentPosition.y + move.y
      };
    }
    
    
    var dragTarget = document.querySelector('#draggable');
    
    var mouseDowns = Kefir.fromEvents(dragTarget, 'mousedown');
    var mouseMoves = Kefir.fromEvents(document, 'mousemove');
    
    
    var moves = mouseDowns.flatMap(function(downEvent) {
      var mouseUp = Kefir.fromEvents(dragTarget, 'mouseup').take(1).onEnd(function(){
        alert('done dragging');
      });
      return mouseMoves.takeUntilBy(mouseUp)
        .diff(eventsPositionDiff, downEvent);
    });
    
    
    
    var position = moves.scan(applyMove, {x: 0, y: 0});
    
    
    // Add side effect
    
    var el = document.querySelector('#draggable');
    position.onValue(function(pos) {
      el.style.top = pos.y + 'px';
      el.style.left = pos.x + 'px';
    });
    #draggable {
        width: 50px;
        height: 50px;
        position: absolute;
        background: #b9ffb9;
        cursor: move;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        padding: .2em;
    }
    <script src="https://cdn.jsdelivr.net/kefir/3.1.0/kefir.js"></script>
    <div id="draggable">Drag me</div>