[英]RxJS: Locked horizontal or vertical mouse dragging
我想構建一個界面,您可以在一定距離后選擇的模式向各個方向拖動。 例如,如果您水平拖動25像素,它將鎖定為該模式並保持在那里,直到您釋放鼠標為止。 如果垂直拖動,它將執行相同的操作。 如果單擊或長時間按住,可能會發生其他操作。
這是說明我的目標的簡化提琴: https : //jsfiddle.net/ud37p0y2/2/
似乎反應式編程對此非常合適,但是我似乎無法弄清楚如何啟動這些模式,然后堅持使用它們,直到釋放鼠標為止。 我的起點是很多拖放示例,但我似乎無法進一步介紹。
一些代碼(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 would i continue from here?
horizontalDrag.subscribe((pos: IPoint) => {
console.log('drag'); // This fires all the time, i'd like to do it once when the mode starts and then something else to be called every time the mouse has moved
});
從這里,我想觀察一下水平拖動,垂直拖動和保持事件。 模式啟動后,其他模式應禁用,例如,拖動不會觸發長按事件。
我會結合使用amb
+ skipWhile
。
amb
會給您鎖定狀態的行為, skipWhile
將阻止事件觸發,直到事件超過閾值一段時間為止。 核心邏輯將如下所示:
//Waits for either X or Y to emit then only propagates that one
return Rx.Observable.amb(
mouseMove
.pluck('clientX')
//Wait until the threshold is reached
.skipWhile(function (x) {
return Math.abs(startAt.clientX - x) < 25;
})
//Transform the 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 for a second, then subscribe to this 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);
編輯1
通過將延續Observable移到amb
並使用delaySubscription
代替了timeout
。
這是代碼的完全修改版本:
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 and hold</li> </ol> <div id="box"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.