Zoeken op website

TypeScript - RxJS6: stream resetten na voltooiing


Ik heb een beetje geëxperimenteerd met RxJS 6. Ik probeer dragstart, dragmove en dragend te implementeren. Dit is de code die ik tot nu toe heb.

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'));

Het probleem is dat de operators takeUntil en first de stream als voltooid markeren. Dit betekent dat dragstart en dragend slechts één keer zullen worden geactiveerd. Is er een manier om de stream op de een of andere manier te resetten nadat dit evenement heeft plaatsgevonden? Bijvoorbeeld door de dragstart stream te resetten wanneer de mouseup stream een evenement ontvangt.


Aanvullende uitleg

In de huidige implementatie zullen dragstart en dragend precies één keer in de console worden gelogd na het laden van de pagina (& slepen). Daarna is de stream voltooid en zullen er geen verdere gebeurtenissen meer doorheen worden gestuurd. Ik wil de stream bij elke sleepoperatie resetten zodat dragstart & dragend bij elke sleepoperatie werken in plaats van alleen bij de eerste na het laden van de pagina.

Huidig gedrag ([] geeft muisactie weer die heeft plaatsgevonden, cursieve tekst is console-uitvoer):

Eerste sleepbewerking

  • [muisknop ingedrukt]
  • dragstart
  • [muisbeweging]
  • slepenbeweging
  • [muis loslaten]
  • dragend

Tweede sleepbewerking

  • [muisknop ingedrukt]
  • (er gebeurt niets, maar dragstart zou naar de console gelogd moeten worden)
  • [muisbeweging]
  • slepenbeweging
  • [muis omhoog]
  • (er gebeurt niets, maar dragend zou naar de console moeten worden gelogd)

Antwoord #1

Bekijk hier een werkend voorbeeld https://codepen.io/anon/pen/bMWjEVenter linkbeschrijving hier

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>

Antwoord #2

Maar je zei om dat te doen :)

Als je de pijp en de "first"-operator uit de dragstart-stream verwijdert

const dragstart = mousedown

de stream zal niet voltooien. De dragmove zal sowieso niet voltooien omdat deze is gekoppeld aan de mousedown, niet aan de dragstart-stream

Als je de resulterende stroom vertelt om alleen de eerste te kiezen, zal de stroom stoppen nadat hij eenmaal heeft uitgezonden.

Deze code zou moeten werken:

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'));