Skip to content

Commit 3ddcb41

Browse files
authored
feat: implement a functionality to enable boundary control for gridster items (#816)
1 parent 7394a2a commit 3ddcb41

File tree

6 files changed

+117
-14
lines changed

6 files changed

+117
-14
lines changed

projects/angular-gridster2/src/lib/gridsterConfig.constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export const GridsterConfigService: GridsterConfig = {
118118
scrollToNewItems: false, // scroll to new items placed in a scrollable view
119119
disableScrollHorizontal: false, // disable horizontal scrolling
120120
disableScrollVertical: false, // disable vertical scrolling
121+
enableBoundaryControl: false, // enable boundary control while dragging items
121122
disableAutoPositionOnConflict: false, // disable auto-position of items on conflict state,
122123
dirType: DirTypes.LTR // page direction, rtl=right to left ltr= left to right, if you use rtl language set dirType to rtl
123124
};

projects/angular-gridster2/src/lib/gridsterConfig.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export interface GridsterConfig {
138138
scrollToNewItems?: boolean;
139139
disableScrollHorizontal?: boolean;
140140
disableScrollVertical?: boolean;
141+
enableBoundaryControl?: boolean;
141142
enableEmptyCellClick?: boolean;
142143
enableEmptyCellContextMenu?: boolean;
143144
enableEmptyCellDrop?: boolean;

projects/angular-gridster2/src/lib/gridsterConfigS.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface GridsterConfigS {
6464
scrollToNewItems: boolean;
6565
disableScrollHorizontal?: boolean;
6666
disableScrollVertical?: boolean;
67+
enableBoundaryControl?: boolean;
6768
enableEmptyCellClick: boolean;
6869
enableEmptyCellContextMenu: boolean;
6970
enableEmptyCellDrop: boolean;

projects/angular-gridster2/src/lib/gridsterDraggable.service.ts

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import { GridsterUtils } from './gridsterUtils.service';
1010

1111
const GRIDSTER_ITEM_RESIZABLE_HANDLER_CLASS = 'gridster-item-resizable-handler';
1212

13+
enum Direction {
14+
UP = 'UP',
15+
DOWN = 'DOWN',
16+
LEFT = 'LEFT',
17+
RIGHT = 'RIGHT'
18+
}
19+
1320
export class GridsterDraggable {
1421
gridsterItem: GridsterItemComponentInterface;
1522
gridster: GridsterComponentInterface;
@@ -163,21 +170,86 @@ export class GridsterDraggable {
163170
dragMove = (e: MouseEvent): void => {
164171
e.stopPropagation();
165172
e.preventDefault();
166-
GridsterUtils.checkTouchEvent(e);
167-
this.offsetLeft = this.gridster.el.scrollLeft - this.gridster.el.offsetLeft;
168-
this.offsetTop = this.gridster.el.scrollTop - this.gridster.el.offsetTop;
169-
scroll(
170-
this.gridster,
171-
this.left,
172-
this.top,
173-
this.width,
174-
this.height,
175-
e,
176-
this.lastMouse,
177-
this.calculateItemPositionFromMousePosition
178-
);
179173

180-
this.calculateItemPositionFromMousePosition(e);
174+
// get the directions of the mouse event
175+
let directions = this.getDirections(e);
176+
177+
if (this.gridster.options.enableBoundaryControl) {
178+
// prevent moving up at the top of gridster
179+
if (
180+
directions.includes(Direction.UP) &&
181+
this.gridsterItem.el.getBoundingClientRect().top <=
182+
this.gridster.el.getBoundingClientRect().top + this.margin
183+
) {
184+
directions = directions.filter(direction => direction != Direction.UP);
185+
e = new MouseEvent(e.type, {
186+
clientX: e.clientX,
187+
clientY: this.lastMouse.clientY
188+
});
189+
}
190+
// prevent moving left at the leftmost column of gridster
191+
if (
192+
directions.includes(Direction.LEFT) &&
193+
this.gridsterItem.el.getBoundingClientRect().left <=
194+
this.gridster.el.getBoundingClientRect().left + this.margin
195+
) {
196+
directions = directions.filter(
197+
direction => direction != Direction.LEFT
198+
);
199+
e = new MouseEvent(e.type, {
200+
clientX: this.lastMouse.clientX,
201+
clientY: e.clientY
202+
});
203+
}
204+
// prevent moving right at the rightmost column of gridster
205+
if (
206+
directions.includes(Direction.RIGHT) &&
207+
this.gridsterItem.el.getBoundingClientRect().right >=
208+
this.gridster.el.getBoundingClientRect().right - this.margin
209+
) {
210+
directions = directions.filter(
211+
direction => direction != Direction.RIGHT
212+
);
213+
e = new MouseEvent(e.type, {
214+
clientX: this.lastMouse.clientX,
215+
clientY: e.clientY
216+
});
217+
}
218+
// prevent moving down at the bottom of gridster
219+
if (
220+
directions.includes(Direction.DOWN) &&
221+
this.gridsterItem.el.getBoundingClientRect().bottom >=
222+
this.gridster.el.getBoundingClientRect().bottom - this.margin
223+
) {
224+
directions = directions.filter(
225+
direction => direction != Direction.DOWN
226+
);
227+
e = new MouseEvent(e.type, {
228+
clientX: e.clientX,
229+
clientY: this.lastMouse.clientY
230+
});
231+
}
232+
}
233+
234+
// do not change item location when there is no direction to go
235+
if (directions.length) {
236+
GridsterUtils.checkTouchEvent(e);
237+
this.offsetLeft =
238+
this.gridster.el.scrollLeft - this.gridster.el.offsetLeft;
239+
this.offsetTop = this.gridster.el.scrollTop - this.gridster.el.offsetTop;
240+
scroll(
241+
this.gridster,
242+
this.left,
243+
this.top,
244+
this.width,
245+
this.height,
246+
e,
247+
this.lastMouse,
248+
this.calculateItemPositionFromMousePosition
249+
);
250+
251+
this.calculateItemPositionFromMousePosition(e);
252+
}
181253
};
182254

183255
calculateItemPositionFromMousePosition = (e: MouseEvent): void => {
@@ -472,4 +544,25 @@ export class GridsterDraggable {
472544
cancelTouchCancel();
473545
}
474546
};
547+
548+
/**
549+
* Returns the list of directions for given mouse event
550+
* @param e Mouse event
551+
* */
552+
private getDirections(e: MouseEvent) {
553+
const directions: string[] = [];
554+
if (this.lastMouse.clientY > e.clientY) {
555+
directions.push(Direction.UP);
556+
}
557+
if (this.lastMouse.clientY < e.clientY) {
558+
directions.push(Direction.DOWN);
559+
}
560+
if (this.lastMouse.clientX < e.clientX) {
561+
directions.push(Direction.RIGHT);
562+
}
563+
if (this.lastMouse.clientX > e.clientX) {
564+
directions.push(Direction.LEFT);
565+
}
566+
return directions;
567+
}
475568
}

src/app/sections/drag/drag.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
>
4848
Disable Horizontal Scroll
4949
</mat-checkbox>
50+
<mat-checkbox
51+
[(ngModel)]="options.enableBoundaryControl"
52+
(ngModelChange)="changedOptions()"
53+
>
54+
Enable Boundary Control
55+
</mat-checkbox>
5056
<mat-form-field>
5157
<input
5258
matInput

src/assets/drag.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
| draggable.dropOverItemsCallback | callback when dragging an item drops over another item | Function(sourceItem, targetItem, grid) | undefined |
1414
| disableScrollHorizontal | enable/disable auto horizontal scrolling when on edge of grid | Boolean | false |
1515
| disableScrollVertical | enable/disable auto vertical scrolling when on edge of grid | Boolean | false |
16+
| enableBoundaryControl | enable/disable boundary control while dragging items | Boolean | false |

0 commit comments

Comments
 (0)