Skip to content

Instantly share code, notes, and snippets.

@ova2
Last active June 16, 2024 04:34
Show Gist options
  • Save ova2/771a4970bbcdc94007caef83f4ef3f48 to your computer and use it in GitHub Desktop.
Save ova2/771a4970bbcdc94007caef83f4ef3f48 to your computer and use it in GitHub Desktop.
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/switchMap'
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/takeUntil';
export class CanvasInteractionManager {
private destroy$ = new Subject<void>();
constructor(component: CanvasComponent) {
this._element = component.nativeElement;
...
}
setupEvents() {
let wheel$ = Observable.fromEvent(this._element, 'wheel')
.takeUntil(this.destroy$)
.do((event: WheelEvent) => {
event.preventDefault();
})
.share();
wheel$
.filter((event: WheelEvent) => !event.shiftKey && !event.ctrlKey)
.subscribe((event: WheelEvent) => this.moveY(event.deltaY));
wheel$
.filter((event: WheelEvent) => event.shiftKey && !event.ctrlKey)
.subscribe((event: WheelEvent) => this.moveX(event.deltaY));
wheel$
.filter((event: WheelEvent) => event.ctrlKey)
.subscribe((event: WheelEvent) => this.zoom(event.clientX, event.clientY, event.deltaY < 0));
let mousedown$ = Observable.fromEvent(this._element, 'mousedown');
let mousemove$ = Observable.fromEvent(document, 'mousemove');
let mouseup$ = Observable.fromEvent(document, 'mouseup');
let mousedrag$ = mousedown$.switchMap((event: MouseEvent) => {
let prevX = event.clientX;
let prevY = event.clientY;
return mousemove$
.map((event: MouseEvent) => {
event.preventDefault();
let delta = {
dx: event.clientX - prevX,
dy: event.clientY - prevY
};
prevX = event.clientX;
prevY = event.clientY;
return delta;
})
.takeUntil(mouseup$);
}).takeUntil(this.destroy$);
mousedrag$.subscribe((delta: { dx, dy }) => {
if (delta.dx === 0 && delta.dy === 0) {
return;
}
this.moveX(delta.dx);
this.moveY(delta.dy);
});
}
destroy() {
this.destroy$.next();
}
private moveX(dx: number) { ... }
private moveY(dy: number) { ... }
private zoom(x: number, y: number, isZoomIn: boolean) { ... }
}
@josephbuchma
Copy link

Hey, thanks for sharing. I'm new to RxJS, but your example seems to be a bit obsolete (does not work with newest version of rxjs).
Here is my attempt to fix it:

import * as rx from 'rxjs'
import * as rxop from 'rxjs/operators'

export class CanvasInteractionManager {
    _element: HTMLCanvasElement

    private destroy$ = new rx.Subject<void>();

    constructor(canvas: HTMLCanvasElement) {
        this._element = canvas;
    }

    setupEvents() {
        let wheel$ = rx.fromEvent(this._element, 'wheel').pipe(
          rxop.takeUntil(this.destroy$),
          rxop.tap((event: WheelEvent) => event.preventDefault()),
          rxop.share()
        )

        wheel$.pipe(
          rxop.filter((event: WheelEvent) => !event.shiftKey && !event.ctrlKey),
        ).subscribe((event: WheelEvent) => this.moveY(event.deltaY));

        wheel$.pipe(
            rxop.filter((event: WheelEvent) => event.shiftKey && !event.ctrlKey)
        ).subscribe((event: WheelEvent) => this.moveX(event.deltaY));

        wheel$.pipe(
            rxop.filter((event: WheelEvent) => event.ctrlKey)
        ).subscribe((event: WheelEvent) => this.zoom(event.clientX, event.clientY, event.deltaY < 0));

        let mousedown$ = rx.fromEvent(this._element, 'mousedown');
        let mousemove$ = rx.fromEvent(document, 'mousemove');
        let mouseup$ = rx.fromEvent(document, 'mouseup');

        let mousedrag$ = mousedown$.pipe(
          rxop.switchMap((event: MouseEvent) => {
            let prevX = event.clientX;
            let prevY = event.clientY;

            return mousemove$.pipe(
              rxop.map((event: MouseEvent) => {
                  event.preventDefault();

                  let delta = {
                      dx: event.clientX - prevX,
                      dy: event.clientY - prevY
                  };
                  prevX = event.clientX;
                  prevY = event.clientY;

                  return delta;
              }),
              rxop.takeUntil(mouseup$)
            )
          }),
          rxop.takeUntil(this.destroy$)
        );

        mousedrag$.subscribe((delta: { dx, dy }) => {
            if (delta.dx === 0 && delta.dy === 0) {
                return;
            }

            this.moveX(delta.dx);
            this.moveY(delta.dy);
        });
    }

    destroy() {
        this.destroy$.next();
    }

    private moveX(dx: number) { /* ... */ }

    private moveY(dy: number) { /* ... */ }

    private zoom(x: number, y: number, isZoomIn: boolean) { /* ... */ }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment