Javascript RxJS:区分单击和拖动
我有一个AngularJS组件,它可以对单击或拖动(调整区域大小)做出反应 我开始在我的应用程序中使用RxJS(ReactiveX),所以我试图找到一个使用它的解决方案。请求的角度很小 为了简化问题(并训练自己),我根据rx.angular.js拖放示例制作了一个滑块指令: 请参阅Slide.js文件(其他代码用于其他实验)。此逻辑的代码为:Javascript RxJS:区分单击和拖动,javascript,angularjs,rxjs,Javascript,Angularjs,Rxjs,我有一个AngularJS组件,它可以对单击或拖动(调整区域大小)做出反应 我开始在我的应用程序中使用RxJS(ReactiveX),所以我试图找到一个使用它的解决方案。请求的角度很小 为了简化问题(并训练自己),我根据rx.angular.js拖放示例制作了一个滑块指令: 请参阅Slide.js文件(其他代码用于其他实验)。此逻辑的代码为: function(scope, element, attributes) { var thumb = element.chil
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' });
});
}
函数(范围、元素、属性)
{
var thumb=element.children(0);
var sliderPosition=元素[0]。getBoundingClientRect()。左;
var sliderWidth=元素[0]。getBoundingClientRect().width;
var thumbPosition=thumb[0].getBoundingClientRect().left;
var thumbWidth=thumb[0]。getBoundingClientRect().width;
//基于rx-angular.js的拖放示例
//获取三大事件
var mousedown=rx.Observable.fromEvent(拇指“mousedown”);
var mousemove=rx.Observable.fromEvent(元素“mousemove”);
var mouseup=rx.Observable.fromEvent($document,'mouseup');
//我想能够检测到一个单一的点击与点击和拖动。
//我想说,如果我们在鼠标下移后很快得到mouseup,那只是一次单击;
//mousedown.delay(200)。takeUntil(mouseup)
//.subscribe(函数(){console.log('Simple click');},未定义,函数(){console.log('Simple click completed');});
var locatedMouseDown=mousedown.map(函数(事件)
{
event.preventDefault();
//log('Click',event.clientX-sliderPosition);
//按下鼠标时计算偏移量
var initialThumbPosition=thumb[0]。getBoundingClientRect()。左-滑块位置;
返回{from:initialThumbPosition,offset:event.clientX-sliderPosition};
});
//将鼠标向下移动与鼠标移动相结合,直到鼠标向上移动
var mousedrag=locatedMouseDown.flatMap(函数(单击信息)
{
返回mousemove.map(函数(事件)
{
var move=event.clientX-sliderPosition-clickInfo.offset;
//console.log('Move',clickInfo);
//计算从鼠标下移到鼠标移动的偏移量
返回clickInfo.from+移动;
}).takeUntil(mouseup);
});
鼠笼
.地图(功能(位置)
{
如果(位置<0)
返回0;
如果(位置>滑块宽度-指宽)
返回滑块宽度-指宽;
返回位置;
})
.订阅(功能(职位)
{
//console.log('拖动',位置);
//更新位置
css({left:position+'px'});
});
}
这主要是D'n'D水平约束和给定范围
现在,我想听听mousedown,如果鼠标在短时间内向上移动(比如说200毫秒,进行调整),我会将其视为单击,并进行特定处理(例如,将位置重置为零)
我尝试了delay().takeUntil(mouseup)
,如另一个SO答案所示,但没有成功。也许还需要一个switch()(以避免走拖动路线)
有什么想法吗?提前感谢。延迟(Xms)不是一个诀窍吗?takeUntil(鼠标)做的与你想要的相反?我的意思是,你想在倒计时之前检测
mouseup
事件发生的时间,而前面提到的技巧是在倒计时之后检测mouseup事件发生的时间
我会围绕这些思路尝试一些东西(目前尚未测试,但希望它能让你朝着积极的方向发展):
想法是将mouseup
事件与延迟后发生的虚拟发射进行比赛,然后看谁获胜。因此,如果<代码>点击$< /代码>发出“NoCeCt”,那么你可以考虑没有点击发生。
希望这能起作用,我将很快进行测试,但如果您在我之前进行测试,请让我知道。您可以使用
timeout
(timeout with
如果您使用的是ReactiveX/RxJS)
如果鼠标在超时之前没有出现,它只会传播一个空的
可观察的。如果是这样,那么下游的观察者将收到一个事件。我还没有尝试(还没有?),因为我第一次尝试了@paulpdniels的答案,这更简单。。。而且有效。但是我很欣赏这个答案,它展示了一个有趣的技巧。谢谢。当然,你选择的答案是最好的。毫无疑问,我不知道那个接线员,他们太多了,你很难理解他们所有的+1,这就是为什么我问问题,因为我必须让我的思维适应Rx的思维方式。。。一旦掌握了基本知识,尝试回答问题也是探索API的一个好方法…:-DIt与timeout()
一起工作。我在版本4.0的RxJS库中没有发现timeoutWith
,但是有一个timeoutWithSelector
,它显然只在lite子库中可用。它似乎与第二个版本的timeout
做了相同的事情。也许这只是一个遗产。不管怎样,它是有效的。所以谢谢。@PhiLhotimeoutWith
是其中的一部分。RxJS 4.0仍在被动扩展项目下,因此它使用的是timeout
。你提到了ReactiveX,这就是我提到它的原因。但我很乐意帮忙!vNext?唉。名称和ESNext一样愚蠢…;-)每个版本都是“下一个”,不知怎的。。。我理解这是为了标记一个重大的更新/更改,但名称仍然没有意义。我想vNext最终会是v.5?无论如何,你把我推向了正确的方向(如果你愿意,请参阅Plunker的更新),再次感谢。
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();
});
var click$ = mousedown.flatMap(function (md) {
return mouseup.timeoutWith(200, Observable.empty());
});