My user should be able to move (or rotate) an object by mouse in a canvas. When mouse events occur the screen coordinates are used to calculate the delta (direction and length)
The problem that you have is that the code is not reactive. In reactive programming all behaviors should be defined at decoration time and only one subscription is required.
Here is an example: Angular2/rxjs mouse translation/rotation
import {Component, NgModule, OnInit, ViewChild} from '@angular/core'
import {BrowserModule, ElementRef, MouseEvent} from '@angular/platform-browser'
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMapTo';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/combineLatest';
import 'rxjs/add/operator/startWith';
@Component({
selector: 'my-app',
styles: [`
canvas{
border: 1px solid red;
}`],
template: `
translate/Rotate by mouse
Translate by delta: {{relativeTo$|async|json}}
Rotate by angle: {{rotateToAngle$|async|json}}
`
})
export class App extends OnInit {
@ViewChild('canvas')
canvas: ElementRef;
relativeTo$: Observable<{dx:number, dy:number, start: MouseEvent}>;
rotateToAngle$: Observable<{angle:number, start: MouseEvent}>;
ngOnInit() {
const canvasNE = this.canvas.nativeElement;
const mouseDown$ = Observable.fromEvent(canvasNE, 'mousedown');
const mouseMove$ = Observable.fromEvent(canvasNE, 'mousemove');
const mouseUp$ = Observable.fromEvent(canvasNE, 'mouseup');
const moveUntilMouseUp$= mouseMove$.takeUntil(mouseUp$);
const startRotate$ = mouseDown$.switchMapTo(moveUntilMouseUp$.startWith(null));
const relativePoint = (start: MouseEvent, end: MouseEvent): {x:number, y:number} =>
(start && end && {
dx: start.clientX - end.clientX,
dy: start.clientY - end.clientY,
start: start
} || {});
this.relativeTo$ = startRotate$
.combineLatest(mouseDown$)
.map(arr => relativePoint(arr[0],arr[1]));
this.rotateToAngle$ = this.relativeTo$
.map((tr) => ({angle: Math.atan2(tr.dy, tr.dx), start: tr.start}));
// this.relativeTo$.subscribe(console.log.bind(console,'rotate:'));
// this.rotateToAngle$.subscribe(console.log.bind(console,'rotate 0:'));
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}