Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RXJS Drag n drop

This questions relates to RXJS. I'm trying to adapt the drag and drop example in github to work for a class of divs not just a single element ID. https://github.com/Reactive-Extensions/RxJS/blob/master/examples/dragndrop/dragndrop.html

simple changes to give the div a class nor an ID dont work and i lose ability to drag the element

3 simple changes:

HTML line 7 i.e. <div class="dragTarget">Drag Me!</div>
CSS line 1 i.e. .dragTarget { style attributes unchanged }
JS line 4 i.e var dragTarget = document.getElementsByClassName('dragTarget');

Im not skilled enough to know if this is a bug in RXJS or that the example is not generalised enough. The documentation on RXJS events suggests these changes should be sufficient. Any help appreciated. Thanks.

like image 310
Laurence Fass Avatar asked May 06 '15 15:05

Laurence Fass


1 Answers

fromEvent will use the on and off methods of any Object you pass it, otherwise it will use addEventListener and removeEventListener. So if you're using jQuery, you can simply select all of them and use that (Observable.fromEvent($('.targetNode'), 'mouseup') for example).

Otherwise, you can use any object with an on and off method to subscribe or unsubscribe from the events, like I'm doing below.

Other than that, you can use the target property on the MouseEvent objects you get in each stream to get the actual DOM node you care to move...

Something like the example below should do the trick.

(function (global) {

  /**
    selectNodes is a method to select a NodeList, but convert it to 
    a type that has `on` and `off` methods RxJS 2 expects to see for `fromEvent`
  */
  function selectNodes(selector) {
    var nodes = document.querySelectorAll(selector);

    return {
      // the selected nodes
      nodes: [].slice.call(this.nodes),

      // subscribe to an event on every selected node
      on: function(eventName, handler) {
        this.nodes.forEach(function(node) { node.addEventListener(eventName, handler); });
      },

      // unsubscribe from the event on every selected node
      off: function(eventName, handler) {
        this.nodes.forEach(function(node) { node.removeEventListener(eventName, handler); });
      }
    };
  }

  function main () {
    // IMPORTANT CHANGE: Use the selectNodes method we made
    var dragTargets = selectNodes('.dragTarget');

    // Get the three major events
    var mouseup   = Rx.Observable.fromEvent(dragTargets, 'mouseup');
    var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
    var mousedown = Rx.Observable.fromEvent(dragTargets, '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,
          target: mm.target, // IMPORTANT CHANGE: the element you care about
        };
      }).takeUntil(mouseup);
    });

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

  main();

}(window));
like image 146
Ben Lesh Avatar answered Sep 26 '22 05:09

Ben Lesh