簡體   English   中英

RxJS:鎖定水平或垂直鼠標拖動

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM