RxJS:锁定的水平或垂直鼠标拖动
RxJS: Locked horizontal or vertical mouse dragging
我想构建一个界面,在这个界面中,您可以在一定距离后选择一个模式,向各个方向拖动。例如,如果你水平拖动25px,它会锁定到该模式,并一直停留在那里,直到你释放鼠标。如果你垂直拖动,它也会做同样的事情。如果长时间点击或按住,可能会发生其他操作。
下面是我的目标的简化小提琴: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
的组合。
- CCD_ 3会给你锁定状态的行为
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>
相关文章:
- EaseJS拖放;放下(动画CC)电影剪辑的鼠标坐标
- 当鼠标悬停在文本中的单词上时显示警报
- 跟踪jqplot垂直折线图的鼠标位置
- 如何使用鼠标滚动控制fullPage.js垂直滑块
- 使用鼠标滚轮和滚动条平滑垂直页面滚动
- jQuery手风琴鼠标悬停和鼠标退出垂直菜单的导航
- 鼠标悬停时垂直自动滚动 - 就像“项目赠品”deviantart.com 一样
- 带有鼠标滚轮的垂直滚动幻灯片
- 尝试在画布中绘制三个矩形以在单击鼠标时垂直增长
- 绑定此鼠标滚轮事件处理程序将禁用垂直滚动
- 基本鼠标水平和垂直滚动
- 垂直滚动鼠标时图像移动
- 我们可以只测量垂直鼠标速度使用光标计
- 鼠标输入功能只能垂直工作
- 只有当鼠标移动是水平的而不是垂直的时候才允许jQuery UI拖动
- 如何通过鼠标停止垂直滚动
- 禁用鼠标垂直滚动
- RxJS:锁定的水平或垂直鼠标拖动
- jQuery鼠标进入/悬停停止垂直旋转木马循环中的动画
- 图像平移效果-垂直-鼠标悬停