Skip to content

Added GridGap functionality to grid component #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ Here is listed the basic API of both KtdGridComponent and KtdGridItemComponent.
/** Layout of the grid. Array of all the grid items with its 'id' and position on the grid. */
@Input() layout: KtdGridLayout;

/** Grid gap in css pixels */
@Input() gap: number = 0;

/**
* Parent element that contains the scroll. If an string is provided it would search that element by id on the dom.
* If no data provided or null autoscroll is not performed.
Expand Down Expand Up @@ -159,7 +162,7 @@ Here is listed the basic API of both KtdGridComponent and KtdGridItemComponent.
- [x] Add dragStartThreshold option to grid items.
- [x] Auto Scroll vertical/horizontal if container is scrollable when dragging a grid item. ([commit](https://github.com/katoid/angular-grid-layout/commit/d137d0e3f40cafdb5fdfd7b2bce4286670200c5d)).
- [x] Grid support for minWidth/maxWidth and minHeight/maxHeight on grid items.
- [ ] Add grid gap feature.
- [x] Add grid gap feature.
- [ ] rowHeight to support also 'fit' as value instead of only CSS pixels ([issue](https://github.com/katoid/angular-grid-layout/issues/1)).
- [ ] Grid support for static grid items.
- [ ] Customizable drag placeholder.
Expand Down
40 changes: 28 additions & 12 deletions projects/angular-grid-layout/src/lib/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,24 @@ function getDragResizeEventData(gridItem: KtdGridItemComponent, layout: KtdGridL


function layoutToRenderItems(config: KtdGridCfg, width: number, height: number): KtdDictionary<KtdGridItemRenderData<number>> {
const {cols, rowHeight, layout} = config;

const {cols, rowHeight, layout, gap} = config;
const widthExcludinggap = width - Math.max((gap * (cols - 1)), 0);
const itemWidthPerColumn = (widthExcludinggap / cols);
const renderItems: KtdDictionary<KtdGridItemRenderData<number>> = {};
for (const item of layout) {
renderItems[item.id] = {
id: item.id,
top: item.y === 0 ? 0 : item.y * rowHeight,
left: item.x * (width / cols),
width: item.w * (width / cols),
height: item.h * rowHeight
top: item.y * rowHeight + gap * item.y,
left: item.x * itemWidthPerColumn + gap * item.x,
width: item.w * itemWidthPerColumn + gap * Math.max(item.w - 1, 0),
height: item.h * rowHeight + gap * Math.max(item.h - 1, 0),
};
}
return renderItems;
}

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

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

private _layout: KtdGridLayout;

/** Grid gap in css pixels */
@Input()
get gap(): number {
return this._gap;
}

set gap(val: number) {
this._gap = Math.max(coerceNumberProperty(val), 0);
}

private _gap: number = 0;

get config(): KtdGridCfg {
return {
cols: this.cols,
rowHeight: this.rowHeight,
layout: this.layout,
preventCollision: this.preventCollision,
gap: this.gap,
};
}

Expand All @@ -236,7 +250,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
}

// Check if wee need to recalculate rendering data.
if (needsCompactLayout || changes.rowHeight) {
if (needsCompactLayout || changes.rowHeight || changes.gap) {
needsRecalculateRenderData = true;
}

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

render() {
Expand Down Expand Up @@ -411,7 +425,8 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
layout: currentLayout,
rowHeight: this.rowHeight,
cols: this.cols,
preventCollision: this.preventCollision
preventCollision: this.preventCollision,
gap: this.gap,
}, this.compactType, {
pointerDownEvent,
pointerDragEvent,
Expand All @@ -421,13 +436,14 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
});
newLayout = layout;

this._height = getGridHeight(newLayout, this.rowHeight);
this._height = getGridHeight(newLayout, this.rowHeight, this.gap);

this._gridItemsRenderData = layoutToRenderItems({
cols: this.cols,
rowHeight: this.rowHeight,
layout: newLayout,
preventCollision: this.preventCollision,
gap: this.gap,
}, gridElemClientRect.width, gridElemClientRect.height);

const placeholderStyles = parseRenderItemToPixels(this._gridItemsRenderData[gridItem.id]);
Expand Down
1 change: 1 addition & 0 deletions projects/angular-grid-layout/src/lib/grid.definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface KtdGridCfg {
rowHeight: number; // row height in pixels
layout: KtdGridLayoutItem[];
preventCollision: boolean;
gap: number;
}

export type KtdGridLayout = KtdGridLayoutItem[];
Expand Down
33 changes: 24 additions & 9 deletions projects/angular-grid-layout/src/lib/utils/grid.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,28 @@ export function ktdGridCompact(layout: KtdGridLayout, compactType: KtdGridCompac
.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 }));
}

function screenXPosToGridValue(screenXPos: number, cols: number, width: number): number {
return Math.round((screenXPos * cols) / width);
function screenXToGridX(screenXPos: number, cols: number, width: number, gap: number): number {
const widthMinusGaps = width - (gap * (cols - 1));
const itemWidth = widthMinusGaps / cols;
const widthMinusOneItem = width - itemWidth;
const colWidthWithGap = widthMinusOneItem / (cols - 1);
return Math.round(screenXPos / colWidthWithGap);
}

function screenYPosToGridValue(screenYPos: number, rowHeight: number, height: number): number {
return Math.round(screenYPos / rowHeight);
function screenYToGridY(screenYPos: number, rowHeight: number, height: number, gap: number): number {
return Math.round(screenYPos / (rowHeight + gap));
}

function screenWidthToGridWidth(gridScreenWidth: number, cols: number, width: number, gap: number): number {
const widthMinusGaps = width - (gap * (cols - 1));
const itemWidth = widthMinusGaps / cols;
const gridScreenWidthMinusFirst = gridScreenWidth - itemWidth;
return Math.round(gridScreenWidthMinusFirst / (itemWidth + gap)) + 1;
}

function screenHeightToGridHeight(gridScreenHeight: number, rowHeight: number, height: number, gap: number): number {
const gridScreenHeightMinusFirst = gridScreenHeight - rowHeight;
return Math.round(gridScreenHeightMinusFirst / (rowHeight + gap)) + 1;
}

/** 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. */
Expand Down Expand Up @@ -80,8 +96,8 @@ export function ktdGridItemDragging(gridItem: KtdGridItemComponent, config: KtdG
// Get layout item position
const layoutItem: KtdGridLayoutItem = {
...draggingElemPrevItem,
x: screenXPosToGridValue(gridRelXPos, config.cols, gridElemClientRect.width),
y: screenYPosToGridValue(gridRelYPos, config.rowHeight, gridElemClientRect.height)
x: screenXToGridX(gridRelXPos , config.cols, gridElemClientRect.width, config.gap),
y: screenYToGridY(gridRelYPos, config.rowHeight, gridElemClientRect.height, config.gap)
};

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


// Get layout item grid position
const layoutItem: KtdGridLayoutItem = {
...draggingElemPrevItem,
w: screenXPosToGridValue(width, config.cols, gridElemClientRect.width),
h: screenYPosToGridValue(height, config.rowHeight, gridElemClientRect.height)
w: screenWidthToGridWidth(width, config.cols, gridElemClientRect.width, config.gap),
h: screenHeightToGridHeight(height, config.rowHeight, gridElemClientRect.height, config.gap)
};

layoutItem.w = limitNumberWithinRange(layoutItem.w, gridItem.minW ?? layoutItem.minW, gridItem.maxW ?? layoutItem.maxW);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
<mat-label>Drag Threshold</mat-label>
<input matInput type="number" [value]="dragStartThreshold + ''" (input)="onDragStartThresholdChange($event)">
</mat-form-field>
<mat-form-field>
<mat-label>Gap</mat-label>
<input matInput type="number" [value]="gap" (input)="onGapChange($event)">
</mat-form-field>
<mat-form-field color="accent">
<mat-label>Transition type</mat-label>
<mat-select [value]="currentTransition" (selectionChange)="onTransitionChange($event)">
Expand Down Expand Up @@ -73,6 +77,7 @@
[compactType]="compactType"
[preventCollision]="preventCollision"
[scrollableParent]="autoScroll ? document : null"
[gap]="gap"
scrollSpeed="4"
(dragStarted)="onDragStarted($event)"
(resizeStarted)="onResizeStarted($event)"
Expand Down
5 changes: 5 additions & 0 deletions projects/demo-app/src/app/playground/playground.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class KtdPlaygroundComponent implements OnInit, OnDestroy {
currentTransition: string = this.transitions[0].value;

dragStartThreshold = 0;
gap = 0;
autoScroll = true;
disableDrag = false;
disableResize = false;
Expand Down Expand Up @@ -147,6 +148,10 @@ export class KtdPlaygroundComponent implements OnInit, OnDestroy {
this.dragStartThreshold = coerceNumberProperty((event.target as HTMLInputElement).value);
}

onGapChange(event: Event) {
this.gap = coerceNumberProperty((event.target as HTMLInputElement).value);
}

generateLayout() {
const layout: KtdGridLayout = [];
for (let i = 0; i < this.cols; i++) {
Expand Down