Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
777 views
in Technique[技术] by (71.8m points)

javascript - RxJs: Drag and Drop example : add mousedragstart

How to implement a mousedragstart Observable using the Drag and Drop RxJs's example.

mousedragstart should be emit before the first mousedrag after a mousedown until the mouseup.

I think we have to play with flatMap/take(1)/takeUntil(mouseup) but I fail every time..


UPDATE

Difficulty here is not avoid mousedrag to be emitted before mousedragstart

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Building on my previous, not-addressing-the-root-problem answer, and the information you've provided, we conceptually have things defined as follows:

var dragTarget = document.getElementById('dragTarget');

var mouseup   = Rx.Observable.fromEvent(document,   'mouseup');
var mousemove = Rx.Observable.fromEvent(document,   'mousemove');
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown');

var dragstart = mousedown.flatMap(() =>
  mousemove
   .where(x => x.movementX !== 0 || x.movementY !== 0)
   .takeUntil(mouseup)
   .take(1)
);

var dragmove = mousedown.flatMap(() =>
  mousemove
    .where(x => x.movementX !== 0 || x.movementY !== 0)
    .takeUntil(mouseup)
);

The problem here is the overlap between the events; in terms of relationship to the underlying events, dragstart is triggered by EXACTLY the same thing as the first dragmove. In this case, order of subscription will determine order of execution, which, as you've said, isn't something you want to rely on. To address this, we must take control of the underlying events.

Here's a simple function that takes an observable and returns an array containing two observables which will be issued the same values as the original observable but in which the events will always be passed to the first observable before the second observable, regardless of which is subscribed to first:

function prioritize(s$) {
  var first = new Rx.Subject();
  var second = s$.do(x => first.onNext(x)).share();

  return [
    Rx.Observable.using(
      () => second.subscribe(() => {}),
      () => first
    ),
    second
  ];
}

From there, we can replace the appropriate parts above with something like this:

var mousedowns = prioritize(mousedown);

var dragstart = mousedowns[0].flatMap(() =>
 mousemove
   .where(x => x.movementX !== 0 || x.movementY !== 0)
   .takeUntil(mouseup)
   .take(1)
);

var dragmove = mousedowns[1].flatMap(() =>
  mousemove
    .where(x => x.movementX !== 0 || x.movementY !== 0)
    .takeUntil(mouseup)
);

dragmove.subscribe(() => console.log('dragmove'));
dragstart.subscribe(() => console.log('dragstart'));

Here's the whole thing working:

https://jsbin.com/qodilerofe/edit?js,console,output


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...