简体   繁体   English

如何使用被动事件流同时处理鼠标和触摸事件

[英]How to handle mouse and touch events simultaneously with reactive event streams

I'm building an audio playback control that lets users scrub back and forth through an audio file. 我正在构建一个音频播放控件,让用户可以在音频文件中来回擦洗。 It needs to work with touch and mouse events. 它需要处理触摸和鼠标事件。 How should I go about managing the events for this with reactive event streams? 我应该如何使用被动事件流来管理事件?

Here's a rough idea of how I would expect to build it. 以下是我希望如何构建它的大致想法。

<div id="timeline">
  <span id="scrubber"></span>
</div>

then, using Bacon.js to create event streams 然后,使用Bacon.js创建事件流

var mousedowns = $('#timeline').asEventStream('mousedown');
var touchstarts = $('#timeline').asEventStream('touchstart');

var starts = Bacon.mergeAll(mousedowns, touchstarts);

var mousemoves = $('#timeline').asEventStream('mousemove');
var touchmoves = $('#timeline').asEventStream('touchmove');

var moves = Bacon.mergeAll(mousemoves, touchmoves);

var mouseups = $('#timeline').asEventStream('mouseup');
var touchends = $('#timeline').asEventStream('touchend');

var ends = Bacon.mergeAll(mouseups, touchends);

starts.onValue(function () {
  var repositionScrubber = moves.onValue(function (ev) {
    $('#scrubber').moveTo(ev.offsetX);
  });
  ends.onValue(function () {
    repositionScrubber.stop();
  });
});

I'm sure that's all sorts of wrong, but I'm really new to handling events with observable streams and I don't know of any good cookbooks for it yet. 我确定这是各种各样的错误,但我真的很擅长处理具有可观察流的事件,我还不知道它有什么好的烹饪书。 Any help will be appreciated! 任何帮助将不胜感激!

This is essentially the canonical drag and drop recipe . 这基本上是规范的拖放配方

The minimum working example in RxJS is something like this: RxJS中的最小工作示例是这样的:

var $timeline = $('#timeline');
var $scrubber = $('#scrubber');

var mouseDown = Rx.Observable.merge(
  Rx.Observable.fromEvent($timeline, 'mousedown'),
  Rx.Observable.fromEvent($timeline, 'touchstart'));

var mouseUp = Rx.Observable.merge(
  Rx.Observable.fromEvent($timeline, 'mouseup'),
  Rx.Observable.fromEvent($timeline, 'touchend'));

var mouseMove = Rx.Observable.merge(
  Rx.Observable.fromEvent($timeline, 'mousemove'),
  Rx.Observable.fromEvent($timeline, 'touchmove'));

var subscription = mouseDown.flatMapLatest(function(md) {

  // calculate offsets when mouse down
  var startX = md.offsetX;

  return mouseMove.takeUntil(mouseUp)
                  .map(function(mm) {
                       mm.preventDefault();

                       return {
                        left: mm.clientX - startX,
                       };
                  });
})
.subscribe(function(e) {
  $scrubber.css(e);
});

 var $timeline = $('#timeline'); var $scrubber = $('#scrubber'); var mouseDown = Rx.Observable.merge( Rx.Observable.fromEvent($timeline, 'mousedown'), Rx.Observable.fromEvent($timeline, 'touchstart')); var mouseUp = Rx.Observable.merge( Rx.Observable.fromEvent($timeline, 'mouseup'), Rx.Observable.fromEvent($timeline, 'touchend')); var mouseMove = Rx.Observable.merge( Rx.Observable.fromEvent($timeline, 'mousemove'), Rx.Observable.fromEvent($timeline, 'touchmove')); var subscription = mouseDown.flatMapLatest(function(md) { // calculate offsets when mouse down var startX = md.offsetX; return mouseMove.takeUntil(mouseUp) .map(function(mm) { mm.preventDefault(); return { left: mm.clientX - startX, }; }); }) .subscribe(function(e) { $scrubber.css(e); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.3/rx.all.js"></script> <div id="timeline" style="height: 100px; width: 100px; background: yellow; position: absolute;"> <span id="scrubber" style="height: 20px; width: 30px; background: green; position: relative;">Foo</span> </div> 

var mousemove = Rx.Observable.merge(
            Rx.Observable.fromEvent(document, 'mousemove')
                .map((e) => { e.preventDefault(); return e; }),
            Rx.Observable.fromEvent(document, 'touchmove'))
                .map((e) => e.touches[0]),
        mouseup = Rx.Observable.merge(
            Rx.Observable.fromEvent(dragTarget, 'mouseup'),
            Rx.Observable.fromEvent(dragTarget, 'touchend')),
        mousedown = Rx.Observable.merge(
            Rx.Observable.fromEvent(dragTarget, 'mousedown'),
            Rx.Observable.fromEvent(dragTarget, 'touchstart')
                .map((e) => {
                    var rect = e.target.getBoundingClientRect();
                    e.offsetX = e.touches[0].pageX - rect.left;
                    e.offsetY = e.touches[0].pageY - rect.top;
                    return e;
                }));

mousedown
    .flatMap((start) => mousemove
        .map((mm) =>({
            left: mm.clientX - start.offsetX,
            top: mm.clientY - start.offsetY
        }))
        .takeUntil(mouseup))
    .subscribe(function (pos) {
        dragTarget.style.top = pos.top + 'px';
        dragTarget.style.left = pos.left + 'px';
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM