TypeScript - RxJS6: לאפס זרם לאחר סיום


שיחקתי קצת עם RxJS 6. אני מנסה ליישם dragstart, dragmove ו-dragend. זה הקוד שיש לי עד עכשיו.

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

הבעיה היא שהאופרטורים takeUntil ו-first מסמנים את הזרם כהושלם. משמעות הדבר היא ש-dragstart ו-dragend יופעלו רק פעם אחת. האם יש דרך ליצור איפוס של הזרם לאחר שהאירוע הזה מתרחש? לדוגמה על ידי איפוס של זרם ה-dragstart כאשר זרם ה-mouseup מקבל אירוע.


הסבר נוסף

במימוש הנוכחי dragstart ו-dragend יירשמו בדיוק פעם אחת בקונסולה לאחר טעינת הדף (וגרירה). לאחר מכן הזרם הושלם ולא יישלחו אירועים נוספים דרכו. אני רוצה לאפס את הזרם בכל פעולת גרירה כדי ש-dragstart ו-dragend יעבדו בכל פעולת גרירה ולא רק בפעם הראשונה לאחר טעינת הדף.

התנהגות נוכחית ([] מייצג פעולה של העכבר שקרתה, טקסט במאונך הוא פלט הקונסולה):

הפעולה הראשונה של גרירה

  • [לחץ-עכבר]
  • תחילת_גרירה
  • [תנועת עכבר]
  • גרור_לזוז
  • [שחרור עכבר]
  • סיום גרירה

פעולת גרירה שנייה

  • [לחץ-עכבר]
  • (לא קורה כלום, עם זאת dragstart אמור להירשם לקונסולה)
  • [תנועת עכבר]
  • גרור_לזוז
  • [שחרור עכבר]
  • (לא קורה כלום, עם זאת dragend אמור להירשם לקונסולה)

תשובה #1

אנא ראה כאן דוגמה פועלת https://codepen.io/anon/pen/bMWjEVenter תיאור הקישור כאן

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>

תשובה #2

אבל אתה אמרת לעשות זאת :)

אם תסיר את הצינור ואת המאיץ "first" מזרם dragstart

const dragstart = mousedown

הזרם לא יושלם. פעולת ה-dragmove לא תושלם בכל מקרה משום שהיא ממופה מ-mousedown, לא מזרם ה-dragstart

אם אתה אומר לזרם הנוצר לבחור רק את הראשון, הזרם יושלם לאחר ששידר פעם אחת.

הקוד הזה אמור לעבוד:

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