Skip to content

Commit 16a3df8

Browse files
author
Matt Lewis
committed
feat(snapGrid): implement draggable snap grids
Closes #4
1 parent d2fdcde commit 16a3df8

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

demo/demo.component.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {Component} from '@angular/core';
66
<div mwlDraggable dropData="foo">
77
Drag me!
88
</div>
9-
<div mwlDraggable dropData="bar">
10-
Or drag me!
9+
<div mwlDraggable dropData="bar" [snapGrid]="{x: 100, y: 100}">
10+
I snap to a 100x100 grid
1111
</div>
1212
<div
1313
[class.dropOverActive]="dropOverActive"

src/draggable.directive.ts

+19
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ type Coordinates = {x: number, y: number};
1212

1313
type DragAxis = {x: boolean, y: boolean};
1414

15+
type SnapGrid = {x?: number, y?: number};
16+
1517
@Directive({
1618
selector: '[mwlDraggable]'
1719
})
@@ -21,6 +23,8 @@ export class Draggable implements OnInit, OnDestroy {
2123

2224
@Input() dragAxis: DragAxis = {x: true, y: true};
2325

26+
@Input() snapGrid: SnapGrid = {};
27+
2428
@Output() dragStart: EventEmitter<Coordinates> = new EventEmitter<Coordinates>();
2529

2630
@Output() dragging: EventEmitter<Coordinates> = new EventEmitter<Coordinates>();
@@ -58,12 +62,27 @@ export class Draggable implements OnInit, OnDestroy {
5862

5963
})
6064
.map((moveData: Coordinates) => {
65+
66+
if (this.snapGrid.x) {
67+
moveData.x = Math.floor(moveData.x / this.snapGrid.x) * this.snapGrid.x;
68+
}
69+
70+
if (this.snapGrid.y) {
71+
moveData.y = Math.floor(moveData.y / this.snapGrid.y) * this.snapGrid.y;
72+
}
73+
74+
return moveData;
75+
})
76+
.map((moveData: Coordinates) => {
77+
6178
if (!this.dragAxis.x) {
6279
moveData.x = 0;
6380
}
81+
6482
if (!this.dragAxis.y) {
6583
moveData.y = 0;
6684
}
85+
6786
return moveData;
6887
})
6988
.takeUntil(Observable.merge(this.mouseUp, this.mouseDown));

test/draggable.directive.spec.ts

+36
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe('draggable directive', () => {
1313
<div
1414
mwlDraggable
1515
[dragAxis]="dragAxis"
16+
[snapGrid]="snapGrid"
1617
(dragStart)="dragStart($event)"
1718
(dragging)="dragging($event)"
1819
(dragEnd)="dragEnd($event)">
@@ -26,6 +27,7 @@ describe('draggable directive', () => {
2627
public dragging: sinon.SinonSpy = sinon.spy();
2728
public dragEnd: sinon.SinonSpy = sinon.spy();
2829
public dragAxis: any = {x: true, y: true};
30+
public snapGrid: any = {};
2931

3032
}
3133

@@ -118,4 +120,38 @@ describe('draggable directive', () => {
118120
expect(fixture.componentInstance.dragEnd).to.have.been.calledWith({x: 0, y: 0});
119121
});
120122

123+
it('should snap all horizontal drags to a grid', () => {
124+
fixture.componentInstance.snapGrid = {x: 10};
125+
fixture.detectChanges();
126+
const draggableElement: HTMLElement = fixture.componentInstance.draggable.element.nativeElement;
127+
triggerDomEvent('mousedown', draggableElement, {clientX: 5, clientY: 10});
128+
triggerDomEvent('mousemove', draggableElement, {clientX: 7, clientY: 12});
129+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 0, y: 2});
130+
triggerDomEvent('mousemove', draggableElement, {clientX: 14, clientY: 18});
131+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 0, y: 8});
132+
triggerDomEvent('mousemove', draggableElement, {clientX: 15, clientY: 20});
133+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 10, y: 10});
134+
triggerDomEvent('mousemove', draggableElement, {clientX: 16, clientY: 22});
135+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 10, y: 12});
136+
triggerDomEvent('mouseup', draggableElement, {clientX: 16, clientY: 22});
137+
expect(fixture.componentInstance.dragEnd).to.have.been.calledWith({x: 10, y: 12});
138+
});
139+
140+
it('should snap all vertical drags to a grid', () => {
141+
fixture.componentInstance.snapGrid = {y: 10};
142+
fixture.detectChanges();
143+
const draggableElement: HTMLElement = fixture.componentInstance.draggable.element.nativeElement;
144+
triggerDomEvent('mousedown', draggableElement, {clientX: 10, clientY: 5});
145+
triggerDomEvent('mousemove', draggableElement, {clientX: 12, clientY: 7});
146+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 2, y: 0});
147+
triggerDomEvent('mousemove', draggableElement, {clientX: 18, clientY: 14});
148+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 8, y: 0});
149+
triggerDomEvent('mousemove', draggableElement, {clientX: 20, clientY: 15});
150+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 10, y: 10});
151+
triggerDomEvent('mousemove', draggableElement, {clientX: 22, clientY: 16});
152+
expect(fixture.componentInstance.dragging).to.have.been.calledWith({x: 12, y: 10});
153+
triggerDomEvent('mouseup', draggableElement, {clientX: 22, clientY: 16});
154+
expect(fixture.componentInstance.dragEnd).to.have.been.calledWith({x: 12, y: 10});
155+
});
156+
121157
});

0 commit comments

Comments
 (0)