Skip to content

Commit

Permalink
feat: use lettable rxjs operators
Browse files Browse the repository at this point in the history
BREAKING CHANGE: rxjs operators will now no longer be added to the observable prototype. Also rxjs
>= 5.5.x or higher is required
  • Loading branch information
Matt Lewis committed Dec 26, 2017
1 parent 91e89a5 commit 9fca12a
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 119 deletions.
197 changes: 105 additions & 92 deletions src/draggable.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import {
} from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/takeLast';
import 'rxjs/add/operator/pairwise';
import 'rxjs/add/operator/share';
import { merge } from 'rxjs/observable/merge';
import { map } from 'rxjs/operators/map';
import { mergeMap } from 'rxjs/operators/mergeMap';
import { takeUntil } from 'rxjs/operators/takeUntil';
import { take } from 'rxjs/operators/take';
import { takeLast } from 'rxjs/operators/takeLast';
import { pairwise } from 'rxjs/operators/pairwise';
import { share } from 'rxjs/operators/share';
import { filter } from 'rxjs/operators/filter';
import { DraggableHelper } from './draggable-helper.provider';

export interface Coordinates {
Expand Down Expand Up @@ -114,96 +115,108 @@ export class DraggableDirective implements OnInit, OnChanges, OnDestroy {
this.checkEventListeners();

const pointerDrag: Observable<any> = this.pointerDown
.filter(() => this.canDrag())
.flatMap((pointerDownEvent: PointerEvent) => {
const currentDrag: Subject<any> = new Subject();

const pointerMove: Observable<Coordinates> = this.pointerMove
.map((pointerMoveEvent: PointerEvent) => {
pointerMoveEvent.event.preventDefault();

return {
currentDrag,
x: pointerMoveEvent.clientX - pointerDownEvent.clientX,
y: pointerMoveEvent.clientY - pointerDownEvent.clientY,
clientX: pointerMoveEvent.clientX,
clientY: pointerMoveEvent.clientY
};
})
.map((moveData: Coordinates) => {
if (this.dragSnapGrid.x) {
moveData.x =
Math.floor(moveData.x / this.dragSnapGrid.x) *
this.dragSnapGrid.x;
}

if (this.dragSnapGrid.y) {
moveData.y =
Math.floor(moveData.y / this.dragSnapGrid.y) *
this.dragSnapGrid.y;
}

return moveData;
})
.map((moveData: Coordinates) => {
if (!this.dragAxis.x) {
moveData.x = 0;
}

if (!this.dragAxis.y) {
moveData.y = 0;
}

return moveData;
})
.filter(
({ x, y }) => !this.validateDrag || this.validateDrag({ x, y })
)
.takeUntil(Observable.merge(this.pointerUp, this.pointerDown))
.share();

pointerMove.take(1).subscribe(() => {
pointerDownEvent.event.preventDefault();

this.zone.run(() => {
this.dragStart.next({ x: 0, y: 0 });
.pipe(filter(() => this.canDrag()))
.pipe(
mergeMap((pointerDownEvent: PointerEvent) => {
const currentDrag: Subject<any> = new Subject();

const pointerMove: Observable<Coordinates> = this.pointerMove
.pipe(
map((pointerMoveEvent: PointerEvent) => {
pointerMoveEvent.event.preventDefault();

return {
currentDrag,
x: pointerMoveEvent.clientX - pointerDownEvent.clientX,
y: pointerMoveEvent.clientY - pointerDownEvent.clientY,
clientX: pointerMoveEvent.clientX,
clientY: pointerMoveEvent.clientY
};
})
)
.pipe(
map((moveData: Coordinates) => {
if (this.dragSnapGrid.x) {
moveData.x =
Math.floor(moveData.x / this.dragSnapGrid.x) *
this.dragSnapGrid.x;
}

if (this.dragSnapGrid.y) {
moveData.y =
Math.floor(moveData.y / this.dragSnapGrid.y) *
this.dragSnapGrid.y;
}

return moveData;
})
)
.pipe(
map((moveData: Coordinates) => {
if (!this.dragAxis.x) {
moveData.x = 0;
}

if (!this.dragAxis.y) {
moveData.y = 0;
}

return moveData;
})
)
.pipe(
filter(
({ x, y }) => !this.validateDrag || this.validateDrag({ x, y })
)
)
.pipe(takeUntil(merge(this.pointerUp, this.pointerDown)))
.pipe(share());

pointerMove.pipe(take(1)).subscribe(() => {
pointerDownEvent.event.preventDefault();

this.zone.run(() => {
this.dragStart.next({ x: 0, y: 0 });
});

this.setCursor(this.dragCursor);

this.draggableHelper.currentDrag.next(currentDrag);
});

this.setCursor(this.dragCursor);

this.draggableHelper.currentDrag.next(currentDrag);
});

pointerMove.takeLast(1).subscribe(({ x, y }) => {
this.zone.run(() => {
this.dragEnd.next({ x, y });
pointerMove.pipe(takeLast(1)).subscribe(({ x, y }) => {
this.zone.run(() => {
this.dragEnd.next({ x, y });
});
currentDrag.complete();
this.setCssTransform(null);
if (this.ghostDragEnabled) {
this.renderer.setStyle(
this.element.nativeElement,
'pointerEvents',
null
);
}
});
currentDrag.complete();
this.setCssTransform(null);
if (this.ghostDragEnabled) {
this.renderer.setStyle(
this.element.nativeElement,
'pointerEvents',
null
);
}
});

return pointerMove;
})
.share();
return pointerMove;
})
)
.pipe(share());

Observable.merge(
pointerDrag.take(1).map(value => [, value]),
pointerDrag.pairwise()
merge(
pointerDrag.pipe(take(1)).pipe(map(value => [, value])),
pointerDrag.pipe(pairwise())
)
.filter(([previous, next]) => {
if (!previous) {
return true;
}
return previous.x !== next.x || previous.y !== next.y;
})
.map(([previous, next]) => next)
.pipe(
filter(([previous, next]) => {
if (!previous) {
return true;
}
return previous.x !== next.x || previous.y !== next.y;
})
)
.pipe(map(([previous, next]) => next))
.subscribe(({ x, y, currentDrag, clientX, clientY }) => {
this.zone.run(() => {
this.dragging.next({ x, y });
Expand Down
58 changes: 31 additions & 27 deletions src/droppable.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import {
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/pairwise';
import 'rxjs/add/operator/filter';
import { distinctUntilChanged } from 'rxjs/operators/distinctUntilChanged';
import { pairwise } from 'rxjs/operators/pairwise';
import { filter } from 'rxjs/operators/filter';
import { map } from 'rxjs/operators/map';
import { mergeMap } from 'rxjs/operators/mergeMap';
import { DraggableHelper } from './draggable-helper.provider';

function isCoordinateWithinRectangle(
Expand Down Expand Up @@ -64,33 +66,33 @@ export class DroppableDirective implements OnInit, OnDestroy {
const droppableRectangle: ClientRect = this.element.nativeElement.getBoundingClientRect();

let currentDragDropData: any;
const overlaps: Observable<
boolean
> = drag.map(({ clientX, clientY, dropData }) => {
currentDragDropData = dropData;
return isCoordinateWithinRectangle(
clientX,
clientY,
droppableRectangle
);
});

const overlapsChanged: Observable<
boolean
> = overlaps.distinctUntilChanged();
const overlaps = drag.pipe(
map(({ clientX, clientY, dropData }) => {
currentDragDropData = dropData;
return isCoordinateWithinRectangle(
clientX,
clientY,
droppableRectangle
);
})
);

const overlapsChanged = overlaps.pipe(distinctUntilChanged());

let dragOverActive: boolean; // TODO - see if there's a way of doing this via rxjs

overlapsChanged.filter(overlapsNow => overlapsNow).subscribe(() => {
dragOverActive = true;
this.zone.run(() => {
this.dragEnter.next({
dropData: currentDragDropData
overlapsChanged
.pipe(filter(overlapsNow => overlapsNow))
.subscribe(() => {
dragOverActive = true;
this.zone.run(() => {
this.dragEnter.next({
dropData: currentDragDropData
});
});
});
});

overlaps.filter(overlapsNow => overlapsNow).subscribe(() => {
overlaps.pipe(filter(overlapsNow => overlapsNow)).subscribe(() => {
this.zone.run(() => {
this.dragOver.next({
dropData: currentDragDropData
Expand All @@ -99,8 +101,10 @@ export class DroppableDirective implements OnInit, OnDestroy {
});

overlapsChanged
.pairwise()
.filter(([didOverlap, overlapsNow]) => didOverlap && !overlapsNow)
.pipe(pairwise())
.pipe(
filter(([didOverlap, overlapsNow]) => didOverlap && !overlapsNow)
)
.subscribe(() => {
dragOverActive = false;
this.zone.run(() => {
Expand All @@ -110,7 +114,7 @@ export class DroppableDirective implements OnInit, OnDestroy {
});
});

drag.flatMap(() => overlaps).subscribe({
drag.pipe(mergeMap(() => overlaps)).subscribe({
complete: () => {
if (dragOverActive) {
this.zone.run(() => {
Expand Down

0 comments on commit 9fca12a

Please sign in to comment.