RxJS:区分单击和拖动
RxJS: distinguish single click from drag
我有一个 AngularJS 组件,它应该对单击或拖动(调整区域大小)作出反应。
我开始在我的应用程序中使用 RxJS (ReactiveX),所以我试图找到一个使用它的解决方案。请求的 Angular 端较小...
为了简化问题(并训练自己),我根据 rx.angular.js 拖放示例制作了一个滑块指令:http://plnkr.co/edit/UqdyB2
请参阅 Slide.js 文件(其他代码用于其他实验)。这个逻辑的代码是:
function(scope, element, attributes)
{
var thumb = element.children(0);
var sliderPosition = element[0].getBoundingClientRect().left;
var sliderWidth = element[0].getBoundingClientRect().width;
var thumbPosition = thumb[0].getBoundingClientRect().left;
var thumbWidth = thumb[0].getBoundingClientRect().width;
// Based on drag'n'drop example of rx-angular.js
// Get the three major events
var mousedown = rx.Observable.fromEvent(thumb, 'mousedown');
var mousemove = rx.Observable.fromEvent(element, 'mousemove');
var mouseup = rx.Observable.fromEvent($document, 'mouseup');
// I would like to be able to detect a single click vs. click and drag.
// I would say if we get mouseup shortly after mousedown, it is a single click;
// mousedown.delay(200).takeUntil(mouseup)
// .subscribe(function() { console.log('Simple click'); }, undefined, function() { console.log('Simple click completed'); });
var locatedMouseDown = mousedown.map(function (event)
{
event.preventDefault();
// console.log('Click', event.clientX - sliderPosition);
// calculate offsets when mouse down
var initialThumbPosition = thumb[0].getBoundingClientRect().left - sliderPosition;
return { from: initialThumbPosition, offset: event.clientX - sliderPosition };
});
// Combine mouse down with mouse move until mouse up
var mousedrag = locatedMouseDown.flatMap(function (clickInfo)
{
return mousemove.map(function (event)
{
var move = event.clientX - sliderPosition - clickInfo.offset;
// console.log('Move', clickInfo);
// calculate offsets from mouse down to mouse moves
return clickInfo.from + move;
}).takeUntil(mouseup);
});
mousedrag
.map(function (position)
{
if (position < 0)
return 0;
if (position > sliderWidth - thumbWidth)
return sliderWidth - thumbWidth;
return position;
})
.subscribe(function (position)
{
// console.log('Drag', position);
// Update position
thumb.css({ left: position + 'px' });
});
}
这主要是 D'n'D 在水平方向和给定范围内受到限制。
现在,我想听听 mousedown,如果在短时间内(比如 200 毫秒,以进行调整)发生鼠标松开,我将其视为单击并进行特定处理(例如,重置位置归零)。
我尝试使用 delay().takeUntil(mouseup)
,如另一个 SO 答案所示,但没有成功。也许也可能需要一个 switch() (以避免走拖拽路线)。
有什么想法吗?提前致谢。
delay(Xms).takeUntil(mouseup)
的伎俩不是与你想要的相反吗?我的意思是,您想检测 mouseup
事件何时在倒计时之前发生,而上述技巧检测 mouseup 事件何时发生在倒计时之后。
我会围绕这些行尝试一些方法(目前尚未测试,但希望它能引导您朝着积极的方向发展):
var click$ = mousedown.flatMap(function ( mouseDownEv ) {
return merge(
Rx.just(mouseDownEv).delay(Xms).map(function ( x ) {return {event : 'noclick'};}),
mouseup.map(function ( mouseUpEv ) {return {event : mouseUpEv};})
).first();
});
我们的想法是让 mouseup
事件与延迟后发生的虚拟排放赛跑,看看谁赢了。所以如果 click$
发出 'noclick' 那么你可以认为没有点击发生。
希望有用,我会尽快测试,但如果你在我之前测试,请告诉我。
您可以使用 timeout
(timeoutWith
如果您使用 ReactiveX/RxJS)
var click$ = mousedown.flatMap(function (md) {
return mouseup.timeoutWith(200, Observable.empty());
});
如果 mouseup 在超时之前没有发生,它只会传播一个空的 Observable
。如果是,那么下游观察者将收到一个事件。
我有一个 AngularJS 组件,它应该对单击或拖动(调整区域大小)作出反应。
我开始在我的应用程序中使用 RxJS (ReactiveX),所以我试图找到一个使用它的解决方案。请求的 Angular 端较小...
为了简化问题(并训练自己),我根据 rx.angular.js 拖放示例制作了一个滑块指令:http://plnkr.co/edit/UqdyB2 请参阅 Slide.js 文件(其他代码用于其他实验)。这个逻辑的代码是:
function(scope, element, attributes)
{
var thumb = element.children(0);
var sliderPosition = element[0].getBoundingClientRect().left;
var sliderWidth = element[0].getBoundingClientRect().width;
var thumbPosition = thumb[0].getBoundingClientRect().left;
var thumbWidth = thumb[0].getBoundingClientRect().width;
// Based on drag'n'drop example of rx-angular.js
// Get the three major events
var mousedown = rx.Observable.fromEvent(thumb, 'mousedown');
var mousemove = rx.Observable.fromEvent(element, 'mousemove');
var mouseup = rx.Observable.fromEvent($document, 'mouseup');
// I would like to be able to detect a single click vs. click and drag.
// I would say if we get mouseup shortly after mousedown, it is a single click;
// mousedown.delay(200).takeUntil(mouseup)
// .subscribe(function() { console.log('Simple click'); }, undefined, function() { console.log('Simple click completed'); });
var locatedMouseDown = mousedown.map(function (event)
{
event.preventDefault();
// console.log('Click', event.clientX - sliderPosition);
// calculate offsets when mouse down
var initialThumbPosition = thumb[0].getBoundingClientRect().left - sliderPosition;
return { from: initialThumbPosition, offset: event.clientX - sliderPosition };
});
// Combine mouse down with mouse move until mouse up
var mousedrag = locatedMouseDown.flatMap(function (clickInfo)
{
return mousemove.map(function (event)
{
var move = event.clientX - sliderPosition - clickInfo.offset;
// console.log('Move', clickInfo);
// calculate offsets from mouse down to mouse moves
return clickInfo.from + move;
}).takeUntil(mouseup);
});
mousedrag
.map(function (position)
{
if (position < 0)
return 0;
if (position > sliderWidth - thumbWidth)
return sliderWidth - thumbWidth;
return position;
})
.subscribe(function (position)
{
// console.log('Drag', position);
// Update position
thumb.css({ left: position + 'px' });
});
}
这主要是 D'n'D 在水平方向和给定范围内受到限制。
现在,我想听听 mousedown,如果在短时间内(比如 200 毫秒,以进行调整)发生鼠标松开,我将其视为单击并进行特定处理(例如,重置位置归零)。
我尝试使用 delay().takeUntil(mouseup)
,如另一个 SO 答案所示,但没有成功。也许也可能需要一个 switch() (以避免走拖拽路线)。
有什么想法吗?提前致谢。
delay(Xms).takeUntil(mouseup)
的伎俩不是与你想要的相反吗?我的意思是,您想检测 mouseup
事件何时在倒计时之前发生,而上述技巧检测 mouseup 事件何时发生在倒计时之后。
我会围绕这些行尝试一些方法(目前尚未测试,但希望它能引导您朝着积极的方向发展):
var click$ = mousedown.flatMap(function ( mouseDownEv ) {
return merge(
Rx.just(mouseDownEv).delay(Xms).map(function ( x ) {return {event : 'noclick'};}),
mouseup.map(function ( mouseUpEv ) {return {event : mouseUpEv};})
).first();
});
我们的想法是让 mouseup
事件与延迟后发生的虚拟排放赛跑,看看谁赢了。所以如果 click$
发出 'noclick' 那么你可以认为没有点击发生。
希望有用,我会尽快测试,但如果你在我之前测试,请告诉我。
您可以使用 timeout
(timeoutWith
如果您使用 ReactiveX/RxJS)
var click$ = mousedown.flatMap(function (md) {
return mouseup.timeoutWith(200, Observable.empty());
});
如果 mouseup 在超时之前没有发生,它只会传播一个空的 Observable
。如果是,那么下游观察者将收到一个事件。