2016-03-11 3 views
2

Как реализовать mousedragstart Наблюдаемый с использованием Drag and Drop RxJs's example.RxJs: пример перетаскивания: добавить mousedragstart

mousedragstart должно быть излучено до первого mousedrag после mousedown до mouseup.

Я думаю, что мы должны играть с flatMap/take(1)/takeUntil(mouseup), но я не каждый раз ..


UPDATE

Сложность здесь не избежать mousedrag испускается перед тем mousedragstart

+0

STH как 'MouseDrag = mousedown.flatMap (_ => MouseMove) .first(). repeat() '? Не должно быть очень далеко от этого, я думаю. – user3743222

ответ

4

здание на моей предыдущей, не-адресации, в-коренную проблему ответа, и информация, которую вы ввели, мы концептуально есть вещи, определенные следующим образом:

var dragTarget = document.getElementById('dragTarget'); 

var mouseup = Rx.Observable.fromEvent(document, 'mouseup'); 
var mousemove = Rx.Observable.fromEvent(document, 'mousemove'); 
var mousedown = Rx.Observable.fromEvent(dragTarget, 'mousedown'); 

var dragstart = mousedown.flatMap(() => 
    mousemove 
    .where(x => x.movementX !== 0 || x.movementY !== 0) 
    .takeUntil(mouseup) 
    .take(1) 
); 

var dragmove = mousedown.flatMap(() => 
    mousemove 
    .where(x => x.movementX !== 0 || x.movementY !== 0) 
    .takeUntil(mouseup) 
); 

Проблема заключается в совпадении событий; в терминах отношения к основным событиям, dragstart запускается ТОЧНО так же, как и первый dragmove. В этом случае порядок подписки определит порядок исполнения, который, как вы сказали, не на что-то, на что вы хотите положиться. Чтобы решить эту проблему, мы должны взять под контроль основные события.

Вот простая функция, которая берет наблюдаемую и возвращает массив, содержащий два наблюдаемых, которые будут выдавать те же значения, что и исходные наблюдаемые, но в которых события всегда будут переданы в первый наблюдаемый перед вторым наблюдаемым, независимо от того, который подписался на первый:

function prioritize(s$) { 
    var first = new Rx.Subject(); 
    var second = s$.do(x => first.onNext(x)).share(); 

    return [ 
    Rx.Observable.using(
    () => second.subscribe(() => {}), 
    () => first 
    ), 
    second 
    ]; 
} 

Оттуда, мы можем заменить соответствующие части выше с чем-то вроде этого:

var mousedowns = prioritize(mousedown); 

var dragstart = mousedowns[0].flatMap(() => 
mousemove 
    .where(x => x.movementX !== 0 || x.movementY !== 0) 
    .takeUntil(mouseup) 
    .take(1) 
); 

var dragmove = mousedowns[1].flatMap(() => 
    mousemove 
    .where(x => x.movementX !== 0 || x.movementY !== 0) 
    .takeUntil(mouseup) 
); 

dragmove.subscribe(() => console.log('dragmove')); 
dragstart.subscribe(() => console.log('dragstart')); 

Вот все это рабочая:

https://jsbin.com/qodilerofe/edit?js,console,output

+0

Это тихое, более сложное для понимания, но оно отлично работает! Благодаря ;) – plone1

0

Он должен быть таким простым, как

var mousedragstart = mousedown.flatMap(() => mousemove.takeUntil(mouseup).take(1)); 

Но это не так. Chrome запускает событие mousemove сразу после mousedown, что приведет к тому, что вышеуказанная логика неправильно выдаст элемент до того, как пользователь начнет перетаскивать. Так что вы на самом деле нужно что-то вроде:

var mousedragstart = mousedown.flatMap(() => 
     mousemove 
     .where(x => x.movementX !== 0 || x.movementY !== 0) 
     .takeUntil(mouseup) 
     .take(1) 
); 
+0

Не работает dragmove излучается перед тач-стартом. – plone1

+0

Что вы называете «dragmove»? Я взглянул на образец, который вы связали, и перечитал свой вопрос, и я не совсем уверен, что вы спрашиваете.Не могли бы вы разместить какой-нибудь пример кода, который показывает проблему? –

+0

[пример кода] (https://plnkr.co/edit/4mR18RXWfZKTbILYlt1i?p=preview) Я хотел бы получить 'dragstart' перед любым' dragmove'. – plone1

0

Альтернативное решение для перетаскивания:

let dragDiv = document.getElementById('drag'); 
let mouseisdown = false; 
let startPos; 

Observable.fromEvent(dragDiv, "mousedown").subscribe((e) => { 
    mouseisdown = true; 
    startPos = { x: e.offsetX, y: e.offsetY} 
}); 
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false); 


Observable 
    .fromEvent(document, "mousemove") 
    .filter(e => mouseisdown) 
    .map((e) => { 
     return { 
      left: e.clientX - startPos.x, 
      top: e.clientY - startPos.y 
     } 
    }) 
    .subscribe(p => { 
    dragDiv.style.top = p.top + "px"; 
    dragDiv.style.left = p.left + "px"; 
}); 

машинопись версия:

let dragDiv = document.getElementById('drag'); 
let mouseisdown = false; 
let startPos; 

Observable.fromEvent(dragDiv, "mousedown").subscribe((e:MouseEvent) => { 
    mouseisdown = true; 
    startPos = { x: e.offsetX, y: e.offsetY} 
}); 
Observable.fromEvent(document, "mouseup").subscribe(e => mouseisdown = false); 


Observable 
    .fromEvent(document, "mousemove") 
    .filter(e => mouseisdown) 
    .map((e:MouseEvent) => { 
     return { 
      left: e.clientX - startPos.x, 
      top: e.clientY - startPos.y 
     } 
    }) 
    .subscribe(p => { 
    dragDiv.style.top = p.top + "px"; 
    dragDiv.style.left = p.left + "px"; 
}); 
Смежные вопросы