Skip to content

Commit a8b129d

Browse files
Devin Harrisllorenspujol
Devin Harris
authored andcommitted
feat(gap): added gap functionality to grid component
1 parent 065889e commit a8b129d

File tree

6 files changed

+67
-22
lines changed

6 files changed

+67
-22
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ Here is listed the basic API of both KtdGridComponent and KtdGridItemComponent.
9494
/** Layout of the grid. Array of all the grid items with its 'id' and position on the grid. */
9595
@Input() layout: KtdGridLayout;
9696

97+
/** Grid gap in css pixels */
98+
@Input() gap: number = 0;
99+
97100
/**
98101
* Parent element that contains the scroll. If an string is provided it would search that element by id on the dom.
99102
* If no data provided or null autoscroll is not performed.
@@ -159,7 +162,7 @@ Here is listed the basic API of both KtdGridComponent and KtdGridItemComponent.
159162
- [x] Add dragStartThreshold option to grid items.
160163
- [x] Auto Scroll vertical/horizontal if container is scrollable when dragging a grid item. ([commit](https://github.com/katoid/angular-grid-layout/commit/d137d0e3f40cafdb5fdfd7b2bce4286670200c5d)).
161164
- [x] Grid support for minWidth/maxWidth and minHeight/maxHeight on grid items.
162-
- [ ] Add grid gap feature.
165+
- [x] Add grid gap feature.
163166
- [ ] rowHeight to support also 'fit' as value instead of only CSS pixels ([issue](https://github.com/katoid/angular-grid-layout/issues/1)).
164167
- [ ] Grid support for static grid items.
165168
- [ ] Customizable drag placeholder.

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

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,24 @@ function getDragResizeEventData(gridItem: KtdGridItemComponent, layout: KtdGridL
4040

4141

4242
function layoutToRenderItems(config: KtdGridCfg, width: number, height: number): KtdDictionary<KtdGridItemRenderData<number>> {
43-
const {cols, rowHeight, layout} = config;
44-
43+
const {cols, rowHeight, layout, gap} = config;
44+
const widthExcludinggap = width - Math.max((gap * (cols - 1)), 0);
45+
const itemWidthPerColumn = (widthExcludinggap / cols);
4546
const renderItems: KtdDictionary<KtdGridItemRenderData<number>> = {};
4647
for (const item of layout) {
4748
renderItems[item.id] = {
4849
id: item.id,
49-
top: item.y === 0 ? 0 : item.y * rowHeight,
50-
left: item.x * (width / cols),
51-
width: item.w * (width / cols),
52-
height: item.h * rowHeight
50+
top: item.y * rowHeight + gap * item.y,
51+
left: item.x * itemWidthPerColumn + gap * item.x,
52+
width: item.w * itemWidthPerColumn + gap * Math.max(item.w - 1, 0),
53+
height: item.h * rowHeight + gap * Math.max(item.h - 1, 0),
5354
};
5455
}
5556
return renderItems;
5657
}
5758

58-
function getGridHeight(layout: KtdGridLayout, rowHeight: number): number {
59-
return layout.reduce((acc, cur) => Math.max(acc, (cur.y + cur.h) * rowHeight), 0);
59+
function getGridHeight(layout: KtdGridLayout, rowHeight: number, gap: number): number {
60+
return layout.reduce((acc, cur) => Math.max(acc, (cur.y + cur.h) * rowHeight + Math.max(cur.y + cur.h - 1, 0) * gap), 0);
6061
}
6162

6263
// eslint-disable-next-line @katoid/prefix-exported-code
@@ -204,12 +205,25 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
204205

205206
private _layout: KtdGridLayout;
206207

208+
/** Grid gap in css pixels */
209+
@Input()
210+
get gap(): number {
211+
return this._gap;
212+
}
213+
214+
set gap(val: number) {
215+
this._gap = Math.max(coerceNumberProperty(val), 0);
216+
}
217+
218+
private _gap: number = 0;
219+
207220
get config(): KtdGridCfg {
208221
return {
209222
cols: this.cols,
210223
rowHeight: this.rowHeight,
211224
layout: this.layout,
212225
preventCollision: this.preventCollision,
226+
gap: this.gap,
213227
};
214228
}
215229

@@ -236,7 +250,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
236250
}
237251

238252
// Check if wee need to recalculate rendering data.
239-
if (needsCompactLayout || changes.rowHeight) {
253+
if (needsCompactLayout || changes.rowHeight || changes.gap) {
240254
needsRecalculateRenderData = true;
241255
}
242256

@@ -284,7 +298,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
284298
calculateRenderData() {
285299
const clientRect = (this.elementRef.nativeElement as HTMLElement).getBoundingClientRect();
286300
this._gridItemsRenderData = layoutToRenderItems(this.config, clientRect.width, clientRect.height);
287-
this._height = getGridHeight(this.layout, this.rowHeight);
301+
this._height = getGridHeight(this.layout, this.rowHeight, this.gap);
288302
}
289303

290304
render() {
@@ -411,7 +425,8 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
411425
layout: currentLayout,
412426
rowHeight: this.rowHeight,
413427
cols: this.cols,
414-
preventCollision: this.preventCollision
428+
preventCollision: this.preventCollision,
429+
gap: this.gap,
415430
}, this.compactType, {
416431
pointerDownEvent,
417432
pointerDragEvent,
@@ -421,13 +436,14 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
421436
});
422437
newLayout = layout;
423438

424-
this._height = getGridHeight(newLayout, this.rowHeight);
439+
this._height = getGridHeight(newLayout, this.rowHeight, this.gap);
425440

426441
this._gridItemsRenderData = layoutToRenderItems({
427442
cols: this.cols,
428443
rowHeight: this.rowHeight,
429444
layout: newLayout,
430445
preventCollision: this.preventCollision,
446+
gap: this.gap,
431447
}, gridElemClientRect.width, gridElemClientRect.height);
432448

433449
const placeholderStyles = parseRenderItemToPixels(this._gridItemsRenderData[gridItem.id]);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface KtdGridCfg {
2121
rowHeight: number; // row height in pixels
2222
layout: KtdGridLayoutItem[];
2323
preventCollision: boolean;
24+
gap: number;
2425
}
2526

2627
export type KtdGridLayout = KtdGridLayoutItem[];

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,28 @@ export function ktdGridCompact(layout: KtdGridLayout, compactType: KtdGridCompac
2121
.map(item => ({ id: item.id, x: item.x, y: item.y, w: item.w, h: item.h, minW: item.minW, minH: item.minH, maxW: item.maxW, maxH: item.maxH }));
2222
}
2323

24-
function screenXPosToGridValue(screenXPos: number, cols: number, width: number): number {
25-
return Math.round((screenXPos * cols) / width);
24+
function screenXToGridX(screenXPos: number, cols: number, width: number, gap: number): number {
25+
const widthMinusGaps = width - (gap * (cols - 1));
26+
const itemWidth = widthMinusGaps / cols;
27+
const widthMinusOneItem = width - itemWidth;
28+
const colWidthWithGap = widthMinusOneItem / (cols - 1);
29+
return Math.round(screenXPos / colWidthWithGap);
2630
}
2731

28-
function screenYPosToGridValue(screenYPos: number, rowHeight: number, height: number): number {
29-
return Math.round(screenYPos / rowHeight);
32+
function screenYToGridY(screenYPos: number, rowHeight: number, height: number, gap: number): number {
33+
return Math.round(screenYPos / (rowHeight + gap));
34+
}
35+
36+
function screenWidthToGridWidth(gridScreenWidth: number, cols: number, width: number, gap: number): number {
37+
const widthMinusGaps = width - (gap * (cols - 1));
38+
const itemWidth = widthMinusGaps / cols;
39+
const gridScreenWidthMinusFirst = gridScreenWidth - itemWidth;
40+
return Math.round(gridScreenWidthMinusFirst / (itemWidth + gap)) + 1;
41+
}
42+
43+
function screenHeightToGridHeight(gridScreenHeight: number, rowHeight: number, height: number, gap: number): number {
44+
const gridScreenHeightMinusFirst = gridScreenHeight - rowHeight;
45+
return Math.round(gridScreenHeightMinusFirst / (rowHeight + gap)) + 1;
3046
}
3147

3248
/** Returns a Dictionary where the key is the id and the value is the change applied to that item. If no changes Dictionary is empty. */
@@ -80,8 +96,8 @@ export function ktdGridItemDragging(gridItem: KtdGridItemComponent, config: KtdG
8096
// Get layout item position
8197
const layoutItem: KtdGridLayoutItem = {
8298
...draggingElemPrevItem,
83-
x: screenXPosToGridValue(gridRelXPos, config.cols, gridElemClientRect.width),
84-
y: screenYPosToGridValue(gridRelYPos, config.rowHeight, gridElemClientRect.height)
99+
x: screenXToGridX(gridRelXPos , config.cols, gridElemClientRect.width, config.gap),
100+
y: screenYToGridY(gridRelYPos, config.rowHeight, gridElemClientRect.height, config.gap)
85101
};
86102

87103
// Correct the values if they overflow, since 'moveElement' function doesn't do it
@@ -143,12 +159,11 @@ export function ktdGridItemResizing(gridItem: KtdGridItemComponent, config: KtdG
143159
const width = clientX + resizeElemOffsetX - (dragElemClientRect.left + scrollDifference.left);
144160
const height = clientY + resizeElemOffsetY - (dragElemClientRect.top + scrollDifference.top);
145161

146-
147162
// Get layout item grid position
148163
const layoutItem: KtdGridLayoutItem = {
149164
...draggingElemPrevItem,
150-
w: screenXPosToGridValue(width, config.cols, gridElemClientRect.width),
151-
h: screenYPosToGridValue(height, config.rowHeight, gridElemClientRect.height)
165+
w: screenWidthToGridWidth(width, config.cols, gridElemClientRect.width, config.gap),
166+
h: screenHeightToGridHeight(height, config.rowHeight, gridElemClientRect.height, config.gap)
152167
};
153168

154169
layoutItem.w = limitNumberWithinRange(layoutItem.w, gridItem.minW ?? layoutItem.minW, gridItem.maxW ?? layoutItem.maxW);

projects/demo-app/src/app/playground/playground.component.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
<mat-label>Drag Threshold</mat-label>
2525
<input matInput type="number" [value]="dragStartThreshold + ''" (input)="onDragStartThresholdChange($event)">
2626
</mat-form-field>
27+
<mat-form-field>
28+
<mat-label>Gap</mat-label>
29+
<input matInput type="number" [value]="gap" (input)="onGapChange($event)">
30+
</mat-form-field>
2731
<mat-form-field color="accent">
2832
<mat-label>Transition type</mat-label>
2933
<mat-select [value]="currentTransition" (selectionChange)="onTransitionChange($event)">
@@ -73,6 +77,7 @@
7377
[compactType]="compactType"
7478
[preventCollision]="preventCollision"
7579
[scrollableParent]="autoScroll ? document : null"
80+
[gap]="gap"
7681
scrollSpeed="4"
7782
(dragStarted)="onDragStarted($event)"
7883
(resizeStarted)="onResizeStarted($event)"

projects/demo-app/src/app/playground/playground.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export class KtdPlaygroundComponent implements OnInit, OnDestroy {
5050
currentTransition: string = this.transitions[0].value;
5151

5252
dragStartThreshold = 0;
53+
gap = 0;
5354
autoScroll = true;
5455
disableDrag = false;
5556
disableResize = false;
@@ -147,6 +148,10 @@ export class KtdPlaygroundComponent implements OnInit, OnDestroy {
147148
this.dragStartThreshold = coerceNumberProperty((event.target as HTMLInputElement).value);
148149
}
149150

151+
onGapChange(event: Event) {
152+
this.gap = coerceNumberProperty((event.target as HTMLInputElement).value);
153+
}
154+
150155
generateLayout() {
151156
const layout: KtdGridLayout = [];
152157
for (let i = 0; i < this.cols; i++) {

0 commit comments

Comments
 (0)