Skip to content

Commit 505c326

Browse files
committed
feat(drag-n-drop): fixed drag between grids, WIP
1 parent ec9693c commit 505c326

File tree

8 files changed

+137
-109
lines changed

8 files changed

+137
-109
lines changed

projects/angular-grid-layout/src/lib/directives/ktd-drag.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ export class KtdDrag<T> implements AfterContentInit, OnDestroy {
191191
this.subscriptions.push(
192192
this._dragHandles.changes.subscribe(() => {
193193
this._dragRef.dragHandles = this._dragHandles.toArray();
194-
})
194+
}),
195+
this.dragStart.subscribe(({event}) => {
196+
this.gridService.startDrag(event, this._dragRef, 'drag');
197+
}),
195198
);
196199
}
197200

projects/angular-grid-layout/src/lib/grid.component.ts

Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
ktdGridItemDragging, ktdGridItemLayoutItemAreEqual,
2828
ktdGridItemResizing
2929
} from './utils/grid.utils';
30-
import {compact, Layout, LayoutItem} from './utils/react-grid-layout.utils';
30+
import {compact, Layout} from './utils/react-grid-layout.utils';
3131
import {
3232
DragActionType,
3333
GRID_ITEM_GET_RENDER_DATA_TOKEN,
@@ -57,7 +57,6 @@ interface KtdGridDrag {
5757
scrollSubscription: Subscription | null;
5858
startEvent: MouseEvent | TouchEvent;
5959
newLayout: Layout | null;
60-
newLayoutItem: LayoutItem | null;
6160
}
6261

6362
interface KtdDragResizeEvent {
@@ -77,7 +76,6 @@ export type KtdResizeEnd = KtdDragResizeEvent;
7776

7877
interface KtdDroppedEvent<T> {
7978
event: PointingDeviceEvent;
80-
previousLayout: KtdGridLayout | null; // Previous layout is null only when dragging ktdDrag
8179
currentLayout: KtdGridLayout;
8280
previousLayoutItem: KtdGridLayoutItem<T> | null; // Previous layout is null only when dragging ktdDrag
8381
currentLayoutItem: KtdGridLayoutItem<T>;
@@ -356,6 +354,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
356354
layout: this.layout,
357355
preventCollision: this.preventCollision,
358356
gap: this.gap,
357+
gridId: this.id,
359358
};
360359
}
361360

@@ -505,7 +504,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
505504
}
506505

507506
private initSubscriptions() {
508-
const itemsConnectedToGrid$ = this.ktdRegistryService.getKtdDragItemsConnectedToGrid(this);
507+
// const itemsConnectedToGrid$ = this.ktdRegistryService.getKtdDragItemsConnectedToGrid(this);
509508
this.subscriptions = [
510509
this._gridItems.changes.pipe(
511510
startWith(this._gridItems),
@@ -536,20 +535,15 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
536535
event.preventDefault();
537536
}
538537

539-
return this.gridService.startDrag(event, gridItem.dragRef, type, this);
540-
}),
538+
const layoutItem = this.layout.find((item) => item.id === gridItem.id);
539+
const renderData = this._gridItemsRenderData[gridItem.id];
541540

542-
itemsConnectedToGrid$.pipe(
543-
startWith(itemsConnectedToGrid$.value),
544-
switchMap((draggableItems) => {
545-
return merge(
546-
...draggableItems.map((draggableItem) => draggableItem.dragStart.pipe(
547-
map(({source, event}) => ({event, draggableItem, source}))
548-
)),
549-
).pipe(exhaustMap((data) => of(data)));
550-
})
551-
).subscribe(({event, draggableItem}) => {
552-
this.gridService.startDrag(event, draggableItem._dragRef, 'drag');
541+
if (layoutItem === undefined || renderData === undefined) {
542+
console.error(`Couldn\'t find the specified grid item for the id: ${gridItem.id}`);
543+
return;
544+
}
545+
546+
return this.gridService.startDrag(event, gridItem.dragRef, type, this, {layoutItem, renderData});
553547
}),
554548
this.dragEntered.subscribe(({event, dragInfo }) => {
555549
this.startRestoreDragSequence(event, dragInfo);
@@ -558,12 +552,11 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
558552
this.pauseDragSequence(dragInfo);
559553
}),
560554
this.gridService.pointerBeforeEnd$.subscribe(({dragInfo}) => {
561-
if (this.drag !== null && dragInfo !== null) {
555+
if (this.drag !== null && dragInfo !== null && dragInfo.currentGrid === this) {
556+
console.log('Grid ', this.id);
562557
this.updateLayout(dragInfo);
563558
this.stopDragSequence(dragInfo);
564559
}
565-
}),
566-
this.gridService.pointerEnd$.subscribe(() => {
567560
this.drag = null;
568561
}),
569562
];
@@ -600,19 +593,10 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
600593
scrollSubscription,
601594
startEvent: event,
602595
newLayout: null,
603-
newLayoutItem: dragInfo.dragRef.itemRef instanceof KtdDrag ? {
604-
id: dragInfo.dragRef.id,
605-
w: 1,
606-
h: 1,
607-
x: -1,
608-
y: -1,
609-
data: dragInfo.dragRef.data,
610-
} : null,
611596
};
612597
}
613598

614599
private pauseDragSequence(dragInfo: PointerEventInfo): void {
615-
616600
// If the drag is a resize, we don't need to pause the drag sequence.
617601
if (dragInfo.type === 'resize') {
618602
return;
@@ -672,7 +656,8 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
672656
// some utilities from 'react-grid-layout' would not work as expected.
673657
//
674658
const currentLayout: KtdGridLayout = this.drag!.newLayout || this.layout;
675-
const ktdLayoutItem = this.drag!.newLayoutItem !== null ? this.drag!.newLayoutItem : currentLayout.find(item => item.id === dragInfo.dragRef.id)!;
659+
// const ktdLayoutItem = dragInfo.fromGrid !== this ? dragInfo.newLayoutItem : currentLayout.find(item => item.id === dragInfo.dragRef.id)!;
660+
const ktdLayoutItem = dragInfo.newLayoutItem;
676661

677662
// Get the correct newStateFunc depending on if we are dragging or resizing
678663
const calcNewStateFunc = dragInfo.type === 'drag' ? ktdGridItemDragging : ktdGridItemResizing;
@@ -684,12 +669,14 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
684669
cols: this.cols,
685670
preventCollision: this.preventCollision,
686671
gap: this.gap,
672+
gridId: this.id,
687673
}, this.compactType, {
688674
pointerDownEvent: this.drag!.startEvent!,
689675
pointerDragEvent,
690676
gridElemClientRect,
691677
dragElemClientRect,
692-
scrollDifference
678+
scrollDifference,
679+
draggingFromOutside: dragInfo.fromGrid !== this,
693680
});
694681
this.drag!.newLayout = layout;
695682

@@ -702,23 +689,24 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
702689
layout: this.drag!.newLayout,
703690
preventCollision: this.preventCollision,
704691
gap: this.gap,
692+
gridId: this.id,
705693
}, gridElemClientRect.width, gridElemClientRect.height, draggedLayoutItem);
706694
this._gridItemsRenderData = dict;
707695

708-
if (this.drag!.newLayoutItem !== null) {
709-
this.drag!.newLayoutItem = draggedLayoutItem;
696+
if (dragInfo.fromGrid !== this) {
697+
dragInfo.newLayoutItem = draggedLayoutItem;
710698
renderData = draggingItem!;
711699
}
712700

713-
const newGridItemRenderData = renderData !== null ? renderData : this._gridItemsRenderData[dragInfo.dragRef.id];
701+
const newGridItemRenderData = renderData !== null && dragInfo.fromGrid !== this ? renderData : this._gridItemsRenderData[dragInfo.dragRef.id];
714702

715703
// Put the real final position to the placeholder element
716704
this.placeholder!.style.width = `${newGridItemRenderData.width}px`;
717705
this.placeholder!.style.height = `${newGridItemRenderData.height}px`;
718706
this.placeholder!.style.transform = `translateX(${newGridItemRenderData.left}px) translateY(${newGridItemRenderData.top}px)`;
719707

720708
// modify the position of the dragged item to be the once we want (for example the mouse position or whatever)
721-
if (renderData !== null) {
709+
if (renderData !== null && dragInfo.fromGrid !== this ) {
722710
renderData = {
723711
...renderData,
724712
...draggedItemPos,
@@ -775,40 +763,77 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
775763

776764
public updateLayout(dragInfo: PointerEventInfo): void {
777765
if (this.drag != null && this.drag.newLayout) {
766+
const currentLayoutItem = dragInfo.fromGrid === null ? {...dragInfo.newLayoutItem, id: this.getNextId()} : dragInfo.newLayoutItem;
778767
const previousLayoutItem = this.layout.find(item => item.id === dragInfo.dragRef.id);
779-
const currentLayoutItem = this.drag!.newLayout.find(item => item.id === dragInfo.dragRef.id);
780-
781-
// Add new item to the layout if it is being dragged from outside the grid.
782-
this.ngZone.run(() => {
783-
// Do not emit when:
784-
// - Drag is a resize and bounds have not changed.
785-
// - Drag is a normal drag and the item is being dragged inside the same grid.
786-
// - We are dragging from outside the grid and the item was dragged into the grid, but then pointer was released outside the grid.
787-
if (dragInfo.type !== 'resize' && this.drag!.newLayoutItem !== null && dragInfo.currentGrid === this) {
788-
this.dropped.emit({
789-
event: dragInfo.moveEvent,
790-
previousLayout: dragInfo.fromGrid !== null ? dragInfo.fromGrid.layout : null,
791-
currentLayout: this.drag!.newLayout!.map(item => ({
792-
id: item.id,
793-
x: item.x,
794-
y: item.y,
795-
w: item.w,
796-
h: item.h,
797-
minW: item.minW,
798-
minH: item.minH,
799-
maxW: item.maxW,
800-
maxH: item.maxH,
801-
data: item.data,
802-
})) as KtdGridLayout,
803-
previousLayoutItem: previousLayoutItem !== undefined ? previousLayoutItem : null,
804-
currentLayoutItem: currentLayoutItem !== undefined ? currentLayoutItem : {...this.drag!.newLayoutItem!, id: this.getNextId()},
805-
});
806-
return;
807-
}
808768

809-
// Emit when we are not dragging or resizing items already inside the grid.
810-
this.layoutUpdated.emit(this.drag!.newLayout!);
811-
});
769+
// Dragging from one grid to another
770+
if (dragInfo.fromGrid !== dragInfo.currentGrid) {
771+
// Add new item to the layout if it is being dragged from outside the grid.
772+
this.ngZone.run(() => {
773+
if (dragInfo.fromGrid !== null) {
774+
dragInfo.fromGrid.layoutUpdated.emit(dragInfo.fromGrid.layout.filter(item => item.id !== dragInfo.dragRef.id));
775+
}
776+
777+
// Do not emit when:
778+
// - Drag is a resize and bounds have not changed.
779+
// - Drag is a normal drag and the item is being dragged inside the same grid.
780+
// - We are dragging from outside the grid and the item was dragged into the grid, but then pointer was released outside the grid.
781+
if (dragInfo.type !== 'resize' && dragInfo.currentGrid === this) {
782+
this.dropped.emit({
783+
event: dragInfo.moveEvent,
784+
currentLayout: this.drag!.newLayout!.map(item => ({
785+
id: item.id,
786+
x: item.x,
787+
y: item.y,
788+
w: item.w,
789+
h: item.h,
790+
minW: item.minW,
791+
minH: item.minH,
792+
maxW: item.maxW,
793+
maxH: item.maxH,
794+
data: item.data,
795+
})) as KtdGridLayout,
796+
previousLayoutItem: previousLayoutItem !== undefined ? previousLayoutItem : null,
797+
currentLayoutItem: currentLayoutItem,
798+
});
799+
return;
800+
}
801+
802+
// Emit when we are not dragging or resizing items already inside the grid.
803+
// this.layoutUpdated.emit(this.drag!.newLayout!);
804+
});
805+
} else {
806+
// Add new item to the layout if it is being dragged from outside the grid.
807+
this.ngZone.run(() => {
808+
// Do not emit when:
809+
// - Drag is a resize and bounds have not changed.
810+
// - Drag is a normal drag and the item is being dragged inside the same grid.
811+
// - We are dragging from outside the grid and the item was dragged into the grid, but then pointer was released outside the grid.
812+
if (dragInfo.type !== 'resize' && dragInfo.fromGrid === null && dragInfo.currentGrid === this) {
813+
this.dropped.emit({
814+
event: dragInfo.moveEvent,
815+
currentLayout: this.drag!.newLayout!.map(item => ({
816+
id: item.id,
817+
x: item.x,
818+
y: item.y,
819+
w: item.w,
820+
h: item.h,
821+
minW: item.minW,
822+
minH: item.minH,
823+
maxW: item.maxW,
824+
maxH: item.maxH,
825+
data: item.data,
826+
})) as KtdGridLayout,
827+
previousLayoutItem: previousLayoutItem !== undefined ? previousLayoutItem : null,
828+
currentLayoutItem: currentLayoutItem,
829+
});
830+
return;
831+
}
832+
833+
// Emit when we are not dragging or resizing items already inside the grid.
834+
this.layoutUpdated.emit(this.drag!.newLayout!);
835+
});
836+
}
812837
}
813838
}
814839

projects/angular-grid-layout/src/lib/grid.definitions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface KtdGridCfg {
3535
layout: KtdGridLayoutItem[];
3636
preventCollision: boolean;
3737
gap: number;
38+
gridId: string;
3839
}
3940

4041
export type KtdGridLayout = KtdGridLayoutItem[];
@@ -68,4 +69,5 @@ export interface KtdDraggingData {
6869
gridElemClientRect: KtdClientRect;
6970
dragElemClientRect: KtdClientRect;
7071
scrollDifference: { top: number, left: number };
72+
draggingFromOutside: boolean;
7173
}

projects/angular-grid-layout/src/lib/grid.service.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
import {Injectable, NgZone} from '@angular/core';
22
import {Observable, Subject, Subscription} from 'rxjs';
3-
import {DragActionType} from "./grid.definitions";
3+
import {DragActionType, KtdGridItemRenderData} from "./grid.definitions";
44
import {DragRef} from "./utils/drag-ref";
55
import {getDragResizeEventData, KtdGridComponent, PointingDeviceEvent} from "./grid.component";
66
import {KtdDrag} from "./directives/ktd-drag";
77
import {ktdOutsideZone} from "./utils/operators";
88
import {takeUntil} from "rxjs/operators";
99
import {ktdPointerMove, ktdPointerUp} from './utils/pointer.utils';
1010
import {KtdRegistryService} from "./ktd-registry.service";
11+
import {LayoutItem} from "./utils/react-grid-layout.utils";
1112

1213

1314
export interface PointerEventInfo {
1415
dragRef: DragRef;
1516
startEvent: PointingDeviceEvent;
1617
moveEvent: PointingDeviceEvent;
1718
type: DragActionType;
19+
newLayoutItem: LayoutItem;
20+
renderData: KtdGridItemRenderData<number> | null;
1821
fromGrid: KtdGridComponent | null; // The grid where the drag started, it can be null if the drag started outside a grid. For example, when dragging from a connected drag item
1922
currentGrid: KtdGridComponent | null;
2023
}
@@ -70,20 +73,34 @@ export class KtdGridService {
7073
* @param type The type of drag sequence.
7174
* @param grid The grid where the drag sequence started. It can be null if the drag sequence started outside a grid.
7275
*/
73-
public startDrag(event: MouseEvent | TouchEvent | PointerEvent, dragRef: DragRef, type: DragActionType, grid: KtdGridComponent | null = null): void {
76+
public startDrag(event: MouseEvent | TouchEvent | PointerEvent, dragRef: DragRef, type: DragActionType, grid: KtdGridComponent | null = null, gridItem: {layoutItem: LayoutItem, renderData: KtdGridItemRenderData<number>} | null = null): void {
7477
// Make sure, this function is only being called once
7578
if (this.drag !== null) {
7679
return;
7780
}
7881

7982
const isKtdDrag = dragRef.itemRef instanceof KtdDrag;
83+
84+
if (!isKtdDrag && gridItem === null) {
85+
throw new Error('layoutItem must be provided when dragging from a connected drag item');
86+
}
87+
8088
this.drag = {
8189
dragRef,
8290
startEvent: event,
8391
moveEvent: event,
8492
type,
8593
fromGrid: isKtdDrag ? null : grid,
8694
currentGrid: null,
95+
newLayoutItem: isKtdDrag ? {
96+
id: dragRef.id,
97+
w: 1,
98+
h: 1,
99+
x: -1,
100+
y: -1,
101+
data: dragRef.data,
102+
} : gridItem!.layoutItem!,
103+
renderData: isKtdDrag ? null : gridItem!.renderData!,
87104
};
88105

89106
if (grid !== null) {

projects/angular-grid-layout/src/lib/ktd-registry.service.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,4 @@ export class KtdRegistryService<T = any> {
110110
this.ktdDragItemConnectedToGrid[dragRef.id].push(grid);
111111
});
112112
}
113-
114-
public getKtdDragItemsConnectedToGrid(grid: KtdGridComponent): BehaviorSubject<KtdDrag<T>[]> {
115-
return this.gridConnectedToKtdDragItems[grid.id] ? this.gridConnectedToKtdDragItems[grid.id] : new BehaviorSubject<KtdDrag<T>[]>([]);
116-
}
117-
118-
public getGridItemsConnectedToGrid(grid: KtdGridComponent): BehaviorSubject<KtdGridItemComponent<T>[]> {
119-
return this.gridConnectedToGridItems[grid.id] ? this.gridConnectedToGridItems[grid.id] : new BehaviorSubject<KtdGridItemComponent<T>[]>([]);
120-
}
121113
}

0 commit comments

Comments
 (0)