Skip to content

Commit

Permalink
feat: option gap supports setting different values for horizontal and…
Browse files Browse the repository at this point in the history
… vertical directions (#104)
  • Loading branch information
coder-layne committed Jun 13, 2024
1 parent 6d6fc6e commit a0ac92d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 57 deletions.
18 changes: 15 additions & 3 deletions src/Grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,12 @@ abstract class Grid<Options extends GridOptions = GridOptions> extends Component

this._im?.destroy();
}

protected getInlineGap(): number {
return this._getDirectionalGap('inline');
}
protected getContentGap(): number {
return this._getDirectionalGap('content');
}
protected checkReady(options: RenderOptions = {}) {
// Grid: renderItems => checkReady => readyItems => applyGrid
const items = this.items;
Expand Down Expand Up @@ -487,6 +492,13 @@ abstract class Grid<Options extends GridOptions = GridOptions> extends Component
protected _updateItems(items: GridItem[]) {
this.itemRenderer.updateEqualSizeItems(items, this.getItems());
}
private _getDirectionalGap(direction: 'inline' | 'content'): number {
const horizontal = this.options.horizontal!;
const gap = this.options.gap!;
if (typeof gap === 'number') return gap;
const isVerticalGap = horizontal && direction === 'inline' || !horizontal && direction === 'content';
return (isVerticalGap ? (gap as any).vertical : (gap as any).horizontal) ?? (DEFAULT_GRID_OPTIONS["gap"] as number);
}
private _renderComplete(e: OnRenderComplete) {
/**
* This event is fired when the Grid has completed rendering.
Expand All @@ -511,11 +523,11 @@ abstract class Grid<Options extends GridOptions = GridOptions> extends Component
start: startOutline,
end: endOutline,
} = this.outlines;
const gap = this.options.gap!;
const contentGap = this.getContentGap();

const endPoint = endOutline.length ? Math.max(...endOutline) : 0;
const startPoint = startOutline.length ? Math.max(...startOutline) : 0;
const contentSize = Math.max(startPoint, endPoint - gap);
const contentSize = Math.max(startPoint, endPoint - contentGap);

this.containerManager.setContentSize(contentSize);
}
Expand Down
33 changes: 17 additions & 16 deletions src/grids/FrameGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ export class FrameGrid extends Grid<FrameGridOptions> {
inlineSize: rectInlineSize,
contentSize: rectContentSize,
} = this.getRectSize(frameInlineSize);
const inlineGap = this.getInlineGap();
const contentGap = this.getContentGap();


const itemsLength = items.length;
Expand All @@ -165,7 +167,7 @@ export class FrameGrid extends Grid<FrameGridOptions> {
const rectsLength = frameRects.length;
let startOutline = range(frameInlineSize).map(() => Infinity);
let endOutline = range(frameInlineSize).map(() => -Infinity);
const frameOutline = frame.outline.map((point) => point * (rectContentSize + gap));
const frameOutline = frame.outline.map((point) => point * (rectContentSize + contentGap));

for (let startIndex = 0; startIndex < itemsLength; startIndex += rectsLength) {
// Compare group's startOutline and startOutline of rect
Expand All @@ -179,16 +181,16 @@ export class FrameGrid extends Grid<FrameGridOptions> {
contentSize: frameRectContentSize,
inlineSize: frameRectInlineSize,
} = frameRects[rectIndex];
const contentPos = startPoint + frameRectContentPos * (rectContentSize + gap);
const inlinePos = frameRectInlinePos * (rectInlineSize + gap);
const contentSize = frameRectContentSize * (rectContentSize + gap) - gap;
const inlineSize = frameRectInlineSize * (rectInlineSize + gap) - gap;
const contentPos = startPoint + frameRectContentPos * (rectContentSize + contentGap);
const inlinePos = frameRectInlinePos * (rectInlineSize + inlineGap);
const contentSize = frameRectContentSize * (rectContentSize + contentGap) - contentGap;
const inlineSize = frameRectInlineSize * (rectInlineSize + inlineGap) - inlineGap;

fillOutlines(startOutline, endOutline, {
inlinePos: frameRectInlinePos,
inlineSize: frameRectInlineSize,
contentPos: contentPos,
contentSize: contentSize + gap,
contentSize: contentSize + contentGap,
});
item.setCSSGridRect({
inlinePos,
Expand Down Expand Up @@ -228,28 +230,27 @@ export class FrameGrid extends Grid<FrameGridOptions> {
return frame.length ? frame[0].length : 0;
}
public getComputedOutlineSize() {
const {
gap,
rectSize: rectSizeOption,
} = this.options;
const { rectSize: rectSizeOption } = this.options;

if (typeof rectSizeOption === "object") {
return rectSizeOption.inlineSize;
}
return rectSizeOption || ((this.getContainerInlineSize()! + gap) / this.getComputedOutlineLength() - gap);
const inlineGap = this.getInlineGap();
return (
rectSizeOption ||
(this.getContainerInlineSize()! + inlineGap) / this.getComputedOutlineLength() - inlineGap
);
}
protected getRectSize(frameInlineSize: number) {
const {
gap,
rectSize: rectSizeOption,
} = this.options;
const { rectSize: rectSizeOption } = this.options;

if (typeof rectSizeOption === "object") {
return rectSizeOption;
}
const inlineGap = this.getInlineGap();
const rectSizeValue = rectSizeOption
? rectSizeOption
: (this.getContainerInlineSize()! + gap) / frameInlineSize - gap;
: (this.getContainerInlineSize()! + inlineGap) / frameInlineSize - inlineGap;

return { inlineSize: rectSizeValue, contentSize: rectSizeValue };
}
Expand Down
21 changes: 9 additions & 12 deletions src/grids/JustifiedGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,8 @@ export class JustifiedGrid extends Grid<JustifiedGridOptions> {
return links[0];
}
private _getExpectedRowSize(items: GridItem[]) {
const {
gap,
} = this.options;
let containerInlineSize = this.getContainerInlineSize()! - gap * (items.length - 1);
const inlineGap = this.getInlineGap();
let containerInlineSize = this.getContainerInlineSize()! - inlineGap * (items.length - 1);
let ratioSum = 0;
let inlineSum = 0;

Expand All @@ -294,14 +292,12 @@ export class JustifiedGrid extends Grid<JustifiedGridOptions> {
return ratioSum ? (containerInlineSize + inlineSum) / ratioSum : 0;
}
private _getExpectedInlineSize(items: GridItem[], rowSize: number) {
const {
gap,
} = this.options;
const inlineGap = this.getInlineGap();
const size = items.reduce((sum, item) => {
return sum + getExpectedColumnSize(item, rowSize);
}, 0);

return size ? size + gap * (items.length - 1) : 0;
return size ? size + inlineGap * (items.length - 1) : 0;
}
private _getCost(
items: GridItem[],
Expand Down Expand Up @@ -375,13 +371,14 @@ export class JustifiedGrid extends Grid<JustifiedGridOptions> {
isEndDirection: boolean,
) {
const {
gap,
isCroppedSize,
displayedRow,
} = this.options;
const sizeRange = this._getSizeRange();
const startPoint = outline[0] || 0;
const containerInlineSize = this.getContainerInlineSize();
const inlineGap = this.getInlineGap();
const contentGap = this.getContentGap();
const groups = splitItems(items, path);
let contentPos = startPoint;
let displayedSize = 0;
Expand All @@ -394,15 +391,15 @@ export class JustifiedGrid extends Grid<JustifiedGridOptions> {
}
const expectedInlineSize = this._getExpectedInlineSize(groupItems, rowSize);

const allGap = gap * (length - 1);
const allGap = inlineGap * (length - 1);
const scale = (containerInlineSize - allGap) / (expectedInlineSize - allGap);

groupItems.forEach((item, i) => {
let columnSize = getExpectedColumnSize(item, rowSize);

const prevItem = groupItems[i - 1];
const inlinePos = prevItem
? prevItem.cssInlinePos! + prevItem.cssInlineSize! + gap
? prevItem.cssInlinePos! + prevItem.cssInlineSize! + inlineGap
: 0;

if (isCroppedSize) {
Expand All @@ -415,7 +412,7 @@ export class JustifiedGrid extends Grid<JustifiedGridOptions> {
contentSize: rowSize,
});
});
contentPos += gap + rowSize;
contentPos += contentGap + rowSize;
if (displayedRow < 0 || rowIndex < displayedRow) {
displayedSize = contentPos;
}
Expand Down
40 changes: 21 additions & 19 deletions src/grids/MasonryGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,13 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
const column = this.getComputedOutlineLength(items);

const {
gap,
align,
observeChildren,
columnSizeRatio,
contentAlign,
} = this.options;
const inlineGap = this.getContentGap();
const contentGap = this.getContentGap();
const outlineLength = outline.length;
const itemsLength = items.length;
const alignPoses = this._getAlignPoses(column, columnSize);
Expand Down Expand Up @@ -168,7 +169,7 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
let contentSize = item.contentSize;
let columnCount = Math.min(
column,
columnAttribute || Math.max(1, Math.ceil((item.inlineSize + gap) / columnDist)),
columnAttribute || Math.max(1, Math.ceil((item.inlineSize + inlineGap) / columnDist)),
);
const maxColumnCount = Math.min(column, Math.max(columnCount, maxColumnAttribute));
let columnIndex = getColumnIndex(endOutline, columnCount, nearestCalculationName, startPos);
Expand Down Expand Up @@ -214,11 +215,11 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
item.cssContentSize = contentSize;
}
const inlinePos = alignPoses[columnIndex];
contentPos = isEndDirection ? contentPos : contentPos - gap - contentSize;
contentPos = isEndDirection ? contentPos : contentPos - contentGap - contentSize;

item.cssInlinePos = inlinePos;
item.cssContentPos = contentPos;
const nextOutlinePoint = isEndDirection ? contentPos + contentSize + gap : contentPos;
const nextOutlinePoint = isEndDirection ? contentPos + contentSize + contentGap : contentPos;

range(columnCount).forEach((indexOffset) => {
endOutline[columnIndex + indexOffset] = nextOutlinePoint;
Expand All @@ -240,10 +241,8 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
};
}
public getComputedOutlineSize(items = this.items) {
const {
gap,
align,
} = this.options;
const { align } = this.options;
const inlineGap = this.getInlineGap();
const containerInlineSize = this.getContainerInlineSize();
const columnSizeOption = this.columnSize || this.outlineSize;
const columnOption = this.column || this.outlineLength;
Expand All @@ -255,9 +254,9 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
if (!columnOption) {
const maxStretchColumnSize = this.maxStretchColumnSize || Infinity;

column = Math.max(1, Math.ceil((containerInlineSize + gap) / (maxStretchColumnSize + gap)));
column = Math.max(1, Math.ceil((containerInlineSize + inlineGap) / (maxStretchColumnSize + inlineGap)));
}
columnSize = (containerInlineSize + gap) / (column || 1) - gap;
columnSize = (containerInlineSize + inlineGap) / (column || 1) - inlineGap;
} else if (columnSizeOption) {
columnSize = columnSizeOption;
} else if (items.length) {
Expand Down Expand Up @@ -288,7 +287,7 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
return columnSize || 0;
}
public getComputedOutlineLength(items = this.items) {
const gap = this.gap;
const inlineGap = this.getInlineGap();
const columnOption = this.column || this.outlineLength;
const columnCalculationThreshold = this.columnCalculationThreshold;
let column = 1;
Expand All @@ -300,17 +299,20 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {

column = Math.min(
items.length,
Math.max(1, Math.floor((this.getContainerInlineSize() + gap)
/ (columnSize - columnCalculationThreshold + gap))),
Math.max(
1,
Math.floor(
(this.getContainerInlineSize() + inlineGap) /
(columnSize - columnCalculationThreshold + inlineGap)
)
)
);
}
return column;
}
private _getAlignPoses(column: number, columnSize: number) {
const {
align,
gap,
} = this.options;
const { align } = this.options;
const inlineGap = this.getInlineGap();
const containerSize = this.getContainerInlineSize();
const indexes = range(column);

Expand All @@ -320,10 +322,10 @@ export class MasonryGrid extends Grid<MasonryGridOptions> {
if (align === "justify" || align === "stretch") {
const countDist = column - 1;

dist = countDist ? Math.max((containerSize - columnSize) / countDist, columnSize + gap) : 0;
dist = countDist ? Math.max((containerSize - columnSize) / countDist, columnSize + inlineGap) : 0;
offset = Math.min(0, containerSize / 2 - (countDist * dist + columnSize) / 2);
} else {
dist = columnSize + gap;
dist = columnSize + inlineGap;
const totalColumnSize = (column - 1) * dist + columnSize;

if (align === "center") {
Expand Down
14 changes: 8 additions & 6 deletions src/grids/PackingGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,16 @@ export class PackingGrid extends Grid<PackingGridOptions> {


public applyGrid(items: GridItem[], direction: "start" | "end", outline: number[]): GridOutlines {
const { aspectRatio, gap } = this.options;
const { aspectRatio } = this.options;
const containerInlineSize = this.getContainerInlineSize();
const containerContentSize = containerInlineSize / aspectRatio;
const inlineGap = this.getInlineGap();
const contentGap = this.getContentGap();
const prevOutline = outline.length ? outline : [0];
const startPoint = direction === "end"
? Math.max(...prevOutline)
: Math.min(...prevOutline) - containerContentSize - gap;
const endPoint = startPoint + containerContentSize + gap;
: Math.min(...prevOutline) - containerContentSize - contentGap;
const endPoint = startPoint + containerContentSize + contentGap;
const container = new BoxModel({});

items.forEach((item) => {
Expand All @@ -127,12 +129,12 @@ export class PackingGrid extends Grid<PackingGridOptions> {

this._findBestFitArea(container, model);
container.push(model);
container.scaleTo(containerInlineSize + gap, containerContentSize + gap);
container.scaleTo(containerInlineSize + inlineGap, containerContentSize + contentGap);
});
items.forEach((item, i) => {
const boxItem = container.items[i];
const inlineSize = boxItem.inlineSize - gap;
const contentSize = boxItem.contentSize - gap;
const inlineSize = boxItem.inlineSize - inlineGap;
const contentSize = boxItem.contentSize - contentGap;
const contentPos = startPoint + boxItem.contentPos;
const inlinePos = boxItem.inlinePos;

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface GridOptions {
* <ko>아이템들 사이의 공간.</ko>
* @default 5
*/
gap?: number;
gap?: number | { horizontal?: number; vertical?: number };
/**
* The prefix to use element's data attribute.
* <ko>엘리먼트의 데이타 속성에 사용할 접두사.</ko>
Expand Down

0 comments on commit a0ac92d

Please sign in to comment.