admin管理员组文章数量:1426051
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
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
-
sth like
mousedrag = mousedown.flatMap(_ => mousemove).first().repeat()
? Should not be very far from that I think. – user3743222 Commented Mar 11, 2016 at 22:40
3 Answers
Reset to default 5Building 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./qodilerofe/edit?js,console,output
It should be something as simple as
var mousedragstart = mousedown.flatMap(() => mousemove.takeUntil(mouseup).take(1));
But it isn't. Chrome raises a mousemove event immediately after mousedown, which will cause the above logic to incorrectly yield an element before the user actually starts dragging. So you actually need something like:
var mousedragstart = mousedown.flatMap(() =>
mousemove
.where(x => x.movementX !== 0 || x.movementY !== 0)
.takeUntil(mouseup)
.take(1)
);
An alternative solution for drag and drop:
let dragDiv = document.getElementById('drag');
let mouseisdown = false;
let startPos;
Observable.fromEvent(dragDiv, "mousedown").subscribe((e) => {
mouseisdown = true;
startPos = { x: e.offsetX, y: e.offsetY}
});
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false);
Observable
.fromEvent(document, "mousemove")
.filter(e => mouseisdown)
.map((e) => {
return {
left: e.clientX - startPos.x,
top: e.clientY - startPos.y
}
})
.subscribe( p => {
dragDiv.style.top = p.top + "px";
dragDiv.style.left = p.left + "px";
});
The typescript version:
let dragDiv = document.getElementById('drag');
let mouseisdown = false;
let startPos;
Observable.fromEvent(dragDiv, "mousedown").subscribe((e:MouseEvent) => {
mouseisdown = true;
startPos = { x: e.offsetX, y: e.offsetY}
});
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false);
Observable
.fromEvent(document, "mousemove")
.filter(e => mouseisdown)
.map((e:MouseEvent) => {
return {
left: e.clientX - startPos.x,
top: e.clientY - startPos.y
}
})
.subscribe( p => {
dragDiv.style.top = p.top + "px";
dragDiv.style.left = p.left + "px";
});
本文标签: javascriptRxJs Drag and Drop exampleadd mousedragstartStack Overflow
版权声明:本文标题:javascript - RxJs: Drag and Drop example : add mousedragstart - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745468688a2659648.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论