javascript - RxJS: Locked horizontal or vertical mouse dragging -


i want build interface can drag in various directions mode selected after distance. instance if drag 25px horizontally locks mode , stays there until release mouse. if drag vertically same. other actions happen if click or press , hold long time.

here's simplified fiddle illustrating goal: https://jsfiddle.net/ud37p0y2/2/

it seems reactive programming perfect can't seem figure out how start these modes , stick them until release mouse. starting point has been many drag , drop examples can't seem take further..

some code (typescript):

var mousedown = rx.observable.fromevent($element[0], 'mousedown').select((event: mouseevent): ipoint => {     event.preventdefault();     return { x: event.clientx, y: event.clienty }; }); var mouseup   = rx.observable.fromevent($element[0], 'mouseup'); var mousemove = rx.observable.fromevent($element[0], 'mousemove'); var mousedrag = mousedown.selectmany((mousedownpos: ipoint) => {     return mousemove.select((event: mouseevent) => {         return {             x: event.clientx - mousedownpos.x,             y: event.clienty - mousedownpos.y         };     }).takeuntil(mouseup); });  var horizontaldrag = mousedrag.filter((pos: ipoint) => {     return pos.x < -25 || pos.x > 25; }); // how continue here?  horizontaldrag.subscribe((pos: ipoint) => {     console.log('drag'); // fires time, i'd once when mode starts , else called every time mouse has moved }); 

from here i'd observable horizontal drag, vertical drag, , hold events. after mode has started other ones should disabled instance drag wouldn't trigger long press events.

i use combination of amb + skipwhile.

  • amb give behavior of locking in state,
  • skipwhile prevent event firing until pass threshold period of time.

the core logic this:

//waits either x or y emit propagates 1 return rx.observable.amb(     mousemove     .pluck('clientx')     //wait until threshold reached     .skipwhile(function (x) {         return math.abs(startat.clientx - x) < 25;     })     //transform outgoing event     .map(function (x) {         return {             prop: 'clientx',             delta: x - startat.clientx         };     }),      mousemove     .pluck('clienty')     .skipwhile(function (y) {         return math.abs(startat.clienty - y) < 25;     })     .map(function (y) {         return {             prop: 'clienty',             delta: y - startat.clienty         };     }),     //if neither propagates second, subscribe instead     mousemove     .startwith(startat)     .delaysubscription(1000)     .tap(function (e) {          box.classname = 'press';          prop = 'timestamp';          box.innerhtml = '';     })     .map(function (e) {          return {             prop: 'timestamp',             delta: e.timestamp - startat.timestamp          };     }))     .takeuntil(mouseup); 

edit 1

replaced timeout moving continuation observable amb , using delaysubscription instead.

and here modified version of code:

var box = document.getelementbyid('box');    var mousedown = rx.observable.fromevent(box, 'mousedown');    var mouseup = rx.observable.fromevent(document.body, 'mouseup');    var mousemove = rx.observable.fromevent(box, 'mousemove')  .tap(function(e) { e.preventdefault(); });    mousedown.flatmaplatest(function (start) {        var startat = start;            box.classname = 'waiting';      box.innerhtml = 'waiting...';        return rx.observable.amb(          mousemove          .pluck('clientx')          .skipwhile(function (x) {              return math.abs(startat.clientx - x) < 25;          })          .map(function (x) {              return {                  prop: 'clientx',                  delta: x - startat.clientx              };          }),                mousemove          .pluck('clienty')          .skipwhile(function (y) {              return math.abs(startat.clienty - y) < 25;          })          .map(function (y) {              return {                  prop: 'clienty',                  delta: y - startat.clienty              };          }),          mousemove          .startwith(startat)          .delaysubscription(1000)          .tap(function (e) {            box.classname = 'press';            prop = 'timestamp';            box.innerhtml = '';          }).map(function (e) {                     return {             prop: 'timestamp',             delta: e.timestamp - startat.timestamp            };          }))          .takeuntil(mouseup);  })  .subscribe(function (x) {      box.innerhtml = x.prop + ': ' + x.delta;  });      mouseup.subscribe(function() {      box.classname = '';      box.innerhtml = '';  });
body {      font: 12px sans-serif;  }  #box {      width: 300px;      height: 300px;      border: 1px #000 solid;      text-align: center;      padding: 20px;      transition: 0.2s background-color;      cursor: pointer;  }  #box.waiting {      background-color: gray;      cursor: move;  }  #box.dragx {      background-color: red;      cursor: ew-resize;  }  #box.dragy {      background-color: green;      cursor: ns-resize;  }  #box.press {      background-color: yellow;      cursor: progress;  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.3/rx.all.js"></script>  <ol>      <li>drag horizontally</li>      <li>release</li>      <li>drag vertically</li>      <li>relase</li>      <li>press , hold</li>  </ol>  <div id="box"></div>


Comments

Popular posts from this blog

java - Andrioid studio start fail: Fatal error initializing 'null' -

android - Gradle sync Error:Configuration with name 'default' not found -

StringGrid issue in Delphi XE8 firemonkey mobile app -