November's Paddleball Marathon

    rxjs-gestures

    1.2.2 • Public • Published

    rxjs-gestures

    Unified mouse + touch interaction as RxJS Observables. Abstracts away mouse vs. touch events so you can get on to more important things.

    import { Gestures } from 'rxjs-gestures';
     
    const rect = document.body.appendChild(document.createElement('div'));
    rect.style.width = '100px';
    rect.style.height = '100px';
    rect.style.border = '1px solid black';
    rect.style.background = 'black';
    rect.style.opacity = 0.35;
    rect.style.transform = 'translate3d(100px, 100px, 0px)';
     
    // Listen to "start" events -- either mousedown or touchstart
    Gestures.start(rect).subscribe(({ pageY, pageX }) =>
        console.log(`start at (${pageX}, ${pageY})`)
    );
     
    // Listen to "move" events -- mousemove or touchmove
    Gestures.move(rect).subscribe(({ pageY, pageX }) =>
        console.log(`end at (${pageX}, ${pageY})`)
    );
     
    // Listen to "end" events -- mouseup or touchend
    Gestures.end(rect).subscribe(({ pageY, pageX }) =>
        console.log(`end at (${pageX}, ${pageY})`)
    );
     
    // Listen to "start" events, but group them into inner Observables by their input
    // identifier. For mouse, there's only one group. For touch, there can be many.
    Gestures.startsById(rect)
        .do((starts) => console.log(`input ${starts.key} just touched the surface`))
        .flatMap((starts) => starts.delay(500))
        .subscribe(({ pageY, pageX, identifier }) =>
            console.log(`got delayed start on ${event.identifier} at (${pageX}, ${pageY})`)
        );
     
    // Listen to "tap" events -- a start, followed by an end, as long as the
    // end is before a certain time *and* within a certain radius from the start.
    Gestures.tap(rect, {
            timeout: 250, /* <-- if end happens after this timeout, the tap cancels */
            radius: { x: 10, y: 10 } /* <-- if input moves more than 10x10px before the timeout, the tap cancels */
        })
        // Composite gestures all use `startsById` internally, so they emit an
        // Observable of the desired gesture for each distinct input device.
        .mergeAll()
        .subscribe(({ pageY, pageX, identifier }) =>
            console.log(`tapped with ${event.identifier} at (${pageX}, ${pageY})`)
        );
     
    // Listen to "press" events -- a start, followed by an end, as long as the
    // end is after a certain time *and* within a certain radius from the start.
    // Passing 0 for delay is equivalent to calling Gestures.startsById()
    Gestures.press(rect, {
            delay: 450, /* <-- if an end occurs before this delay, the press cancels */
            radius: { x: 10, y: 10 } /* <-- if input moves more than 10x10px before the delay, the press cancels */
        })
        .mergeAll()
        .subscribe(({ pageY, pageX, identifier }) =>
            console.log(`pressed with ${event.identifier} at (${pageX}, ${pageY})`)
        );
     
    // Listen to "pan" events -- a press, followed by any number of moves, then an end.
    // Internally, pan uses Gestures.press(), so pan-immediate vs. pan-after-long-press
    // is handled in the same way.
    Gestures.pan(rect, {
            /*delay: 450, <-- uncomment for long press */
            /*radius: { x: 50, y: 50 } <-- uncomment to change the invalidation area */
        })
        .mergeAll()
        .subscribe(({ pageY, pageX, identifier }) =>
            console.log(`panning with ${event.identifier} at (${pageX}, ${pageY})`)
        );
     
    // Listen for "pan" events
    Gestures.pan(rect).flatMap((pan) =>
        // For each input (mouse, finger, etc.), convert the pan's coorinates
        // into  rect coordinates. When the pan completes, decelerate from the
        // pan's end velocity vector to zero. Essentially this "fakes" more
        // move events, but the subscriber doesn't know the difference.
        pan .decelerate()
            .scan(({ top, left }, { movementX, movementY, event }) => ({
                top: top + movementY,
                left: left + movementX,
                target: event.target,
            }), rect.getBoundingClientRect())
        )
        // Move the rectangle
        .subscribe(({ top, left, target }) => {
            rect.style.transform = `translate3d(${left}px, ${top}px, 0px)`;
        });
     

    Install

    npm i rxjs-gestures

    DownloadsWeekly Downloads

    71

    Version

    1.2.2

    License

    Apache-2.0

    Unpacked Size

    336 kB

    Total Files

    54

    Last publish

    Collaborators

    • ptaylor