title: RxJS: distinguish single click from drag
body: <p>I have an AngularJS component that should react to either a single click or a drag (resizing an area).</p>
  
  <p>I started to use RxJS (ReactiveX) in my application, so I try to find a solution using it. The Angular side of the request is minor...</p>
  
  <p>To simplify the problem (and to train myself), I made a slider directive, based on the rx.angular.js drag'n'drop example: <a href="http://plnkr.co/edit/UqdyB2" rel="noreferrer">http://plnkr.co/edit/UqdyB2</a>
  See the Slide.js file (the other code is for other experiments). The code of this logic is:</p>
  
  <pre><code>    function(scope, element, attributes)
      {
        var thumb = element.children(0);
        var sliderPosition = element[0].getBoundingClientRect().left;
        var sliderWidth = element[0].getBoundingClientRect().width;
        var thumbPosition = thumb[0].getBoundingClientRect().left;
        var thumbWidth = thumb[0].getBoundingClientRect().width;
  
        // Based on drag'n'drop example of rx-angular.js
        // Get the three major events
        var mousedown = rx.Observable.fromEvent(thumb,     'mousedown');
        var mousemove = rx.Observable.fromEvent(element,   'mousemove');
        var mouseup   = rx.Observable.fromEvent($document, 'mouseup');
  
        // I would like to be able to detect a single click vs. click and drag.
        // I would say if we get mouseup shortly after mousedown, it is a single click;
        // mousedown.delay(200).takeUntil(mouseup)
        //   .subscribe(function() { console.log('Simple click'); }, undefined, function() { console.log('Simple click completed'); });
  
        var locatedMouseDown = mousedown.map(function (event) 
        {
          event.preventDefault();
          // console.log('Click', event.clientX - sliderPosition);
          // calculate offsets when mouse down
          var initialThumbPosition = thumb[0].getBoundingClientRect().left - sliderPosition;
          return { from: initialThumbPosition, offset: event.clientX - sliderPosition };
        });
  
        // Combine mouse down with mouse move until mouse up
        var mousedrag = locatedMouseDown.flatMap(function (clickInfo) 
        {
          return mousemove.map(function (event)
          {
            var move = event.clientX - sliderPosition - clickInfo.offset;
            // console.log('Move', clickInfo);
            // calculate offsets from mouse down to mouse moves
            return clickInfo.from + move;
          }).takeUntil(mouseup);
        });
  
        mousedrag 
          .map(function (position)
          {
            if (position &lt; 0)
              return 0;
            if (position &gt; sliderWidth - thumbWidth)
              return sliderWidth - thumbWidth;
            return position;
          })
          .subscribe(function (position) 
          {
            // console.log('Drag', position);
            // Update position
            thumb.css({ left: position + 'px' });
          });
      }
  </code></pre>
  
  <p>That's mostly D'n'D constrained horizontally and to a given range.</p>
  
  <p>Now, I would like to listen to mousedown, and if mouse up happens within a short while (say 200 ms, to adjust), I see it as a click and I do a specific treatment (eg. resetting the position to zero).</p>
  
  <p>I tried with <code>delay().takeUntil(mouseup)</code>, as seen in another SO answer, without success. Perhaps a switch() might be needed, too (to avoid going the drag route).</p>
  
  <p>Any idea? Thanks in advance.</p>