typescript - RxJS6: zresetuj strumień po zakończeniu
Trochę bawiłem się RxJS 6. Próbuję zaimplementować dragstart, dragmove i dragend. Oto kod, który mam do tej pory.
import { fromEvent } from 'rxjs';
import { concatMap } from 'rxjs/internal/operators/concatMap';
import { map } from 'rxjs/internal/operators/map';
import { takeUntil } from 'rxjs/internal/operators/takeUntil';
import { repeat } from 'rxjs/internal/operators/repeat';
import { first } from 'rxjs/internal/operators/first';
const mousedown = fromEvent<MouseEvent>(window, 'mousedown');
const mousemove = fromEvent<MouseEvent>(window, 'mousemove');
const mouseup = fromEvent<MouseEvent>(window, 'mouseup');
const dragstart = mousedown.pipe(
first()
);
const dragmove = mousedown.pipe(
concatMap((dragStartEvent) => mousemove.pipe(
takeUntil(mouseup))
)
);
const dragend = mousedown.pipe(
(dragEvent) => mouseup.pipe(first())
);
const log = (prefix: string) => (data: MouseEvent) => console.log(`${prefix}: x: ${data.clientX}, y:${data.clientY}`);
dragstart.subscribe(log('dragstart'));
dragmove.subscribe(log('dragmove'));
dragend.subscribe(log('dragend'));
Problem polega na tym, że operatory takeUntil i first oznaczają strumień jako zakończony. Oznacza to, że dragstart i dragend będą wywoływane tylko raz. Czy istnieje sposób, aby w jakiś sposób zresetować strumień po wystąpieniu tego zdarzenia? Na przykład poprzez zresetowanie strumienia dragstart, gdy strumień mouseup odbierze zdarzenie.
Dodatkowe wyjaśnienie
W obecnej implementacji dragstart i dragend będą logowane do konsoli dokładnie raz po załadowaniu strony (i przeciąganiu). Po tym strumień zostaje zakończony i żadne dalsze zdarzenia nie będą przez niego przesyłane. Chcę zresetować strumień przy każdej operacji przeciągania, aby dragstart i dragend działały przy każdej operacji przeciągania, a nie tylko przy pierwszej po załadowaniu strony.
Aktualne zachowanie ([] oznacza wykonane działanie myszką, tekst kursywą to wynik konsoli):
Pierwsza operacja przeciągania
- [naciśnięcie_myszy]
- rozpoczęcie przeciągania
- [ruchmyszy]
- przesuwanie
- [puszczenie_myszy]
- koniec przeciągania
Druga operacja przeciągania
- [naciśnięcie_myszy]
- (nic się nie dzieje, jednak dragstart powinien być zarejestrowany w konsoli)
- [ruchmyszy]
- przeciągnij
- [mouseup]
- (nic się nie dzieje, jednak dragend powinien być zarejestrowany w konsoli)
Odpowiedź #1
Proszę zobaczyć tutaj działający przykład https://codepen.io/anon/pen/bMWjEVwpisz opis linku tutaj
const { fromEvent } = Rx.Observable;
const target = document.querySelector('.box');
const mouseup = fromEvent(target, 'mouseup');
const mousemove = fromEvent(document, 'mousemove');
const mousedown = fromEvent(target, 'mousedown');
let log = (prefix: string, x:number, y:number) => console.log(`${prefix}: x: ${x}, y:${y}`);
const mousedrag = mousedown.selectMany((md) => {
const startX = md.clientX + window.scrollX,
startY = md.clientY + window.scrollY,
startLeft = parseInt(md.target.style.left, 10) || 0,
startTop = parseInt(md.target.style.top, 10) || 0;
return mousemove.map((mm) => {
mm.preventDefault();
log('mousemove',mm.clientX, mm.clientY);
return {
left: startLeft + mm.clientX - startX,
top: startTop + mm.clientY - startY
};
}).takeUntil(mouseup);
});
subscription = mousedrag.subscribe((pos) => {
log('dragstart',pos.top, pos.left)
target.style.top = pos.top + 'px';
target.style.left = pos.left + 'px';
});.box {
position: relative;
width: 100px;
height: 100px;
background: red;
cursor: pointer;
border:solid 10px green;
}<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.2/rx.all.js"></script>
<div class="box"></div>Odpowiedź #2
Ale powiedziałeś, żeby tak zrobić :)
Jeśli usuniesz rurkę i operator „first” ze strumienia dragstart
const dragstart = mousedown
strumień nie zakończy się. Dragmove i tak się nie zakończy, ponieważ jest mapowany z mousedown, a nie ze strumienia dragstart
Jeśli powiesz powstałemu strumieniowi, aby wybrał tylko pierwszy element, strumień zakończy się po jednorazowym wysłaniu.
Ten kod powinien działać:
const mousedown = fromEvent<MouseEvent>(window, 'mousedown');
const mousemove = fromEvent<MouseEvent>(window, 'mousemove');
const mouseup = fromEvent<MouseEvent>(window, 'mouseup');
// I dont think it's necessary to duplicate
const dragstart = mousedown
// No need to map to something else
const dragend = mouseup
const dragmove = dragstart.pipe(
concatMapTo(
mousemove.pipe(
takeUntil( dragend )
)
)
);
const log = (prefix: string) => (data: MouseEvent) => console.log(`${prefix}: x: ${data.clientX}, y:${data.clientY}`);
dragstart.subscribe(log('dragstart'));
dragmove.subscribe(log('dragmove'));
dragend.subscribe(log('dragend'));
