Skip to content

Commit

Permalink
feat: support size-group, not-equal-size attribute (#533)
Browse files Browse the repository at this point in the history
* feat: support size-group, not-equal-size attribute

* chore: update @egjs/grid version
  • Loading branch information
daybrush committed Mar 13, 2023
1 parent 5e3d9fe commit f693db9
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 24 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,40 @@ const grid = new MasonryInfiniteGrid(container, {
grid.renderItems();
```


## Pre-guess size for performance or invisible items.
### What if all items were the same size?
If you use the `isEqualSize` option, all items are considered to be the same size.
Each resize only calculates the size of one item.
Add `data-grid-not-equal-size="true"` attribute if there is an exceptional item whose size needs to be calculated while using isEqualSize.
```html
<div class="item item1"></div>
<div class="item item1"></div>
<div class="item item1"></div>
<!--item2 is a different size than item1.-->
<div class="item item2" data-grid-not-equal-size="true"></div>
```

### What if a size group exists?

`isEqualSize` assumes all items are equal. But if there are more than two size-groups, use `data-grid-size-group`.


```html
<!--item1 has the same size.-->
<div class="item item1" data-grid-size-group="1"></div>
<div class="item item1" data-grid-size-group="1"></div>
<!--item2 has the same size.-->
<div class="item item2" data-grid-size-group="2"></div>
<div class="item item2" data-grid-size-group="2"></div>
```


### What if all items don't change size?
If all items do not have a constant size, use the `isConstantSize` option. Resizing doesn't calculate the item's size.
If you want to recalculate, use `.updateItems(items, { useOrgResize: true })` method or `.renderItems({ useOrgResize: true })` method.


## 📦 Packages
|Package|Version|Description|
|:-----:|:-----:|:-----:|
Expand Down
2 changes: 1 addition & 1 deletion packages/infinitegrid/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"arrow-parens": ["error", "always"],
"@typescript-eslint/naming-convention": [
"error",
{ "selector": "default", "modifiers": ["protected"], "format": ["camelCase"], "leadingUnderscore": "forbid" },
{ "selector": "default", "modifiers": ["protected"], "format": ["camelCase"], "leadingUnderscore": "allow" },
{ "selector": "default", "modifiers": ["private"], "format": ["camelCase"], "leadingUnderscore": "require" }
],
"no-empty-interface": "off",
Expand Down
36 changes: 36 additions & 0 deletions packages/infinitegrid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,42 @@ const grid = new MasonryInfiniteGrid(container, {
grid.renderItems();
```


## Pre-guess size for performance or invisible items.
### What if all items were the same size?
If you use the `isEqualSize` option, all items are considered to be the same size.
Each resize only calculates the size of one item.
Add `data-grid-not-equal-size="true"` attribute if there is an exceptional item whose size needs to be calculated while using isEqualSize.
```html
<div class="item item1"></div>
<div class="item item1"></div>
<div class="item item1"></div>
<!--item2 is a different size than item1.-->
<div class="item item2" data-grid-not-equal-size="true"></div>
```

### What if a size group exists?

`isEqualSize` assumes all items are equal. But if there are more than two size-groups, use `data-grid-size-group`.


```html
<!--item1 has the same size.-->
<div class="item item1" data-grid-size-group="1"></div>
<div class="item item1" data-grid-size-group="1"></div>
<!--item2 has the same size.-->
<div class="item item2" data-grid-size-group="2"></div>
<div class="item item2" data-grid-size-group="2"></div>
```


### What if all items don't change size?

If all items do not have a constant size, use the `isConstantSize` option. Resizing doesn't calculate the item's size.
If you want to recalculate, use `.updateItems(items, { useOrgResize: true })` method or `.renderItems({ useOrgResize: true })` method.



## 📦 Packages
|Package|Version|Description|
|:-----:|:-----:|:-----:|
Expand Down
4 changes: 2 additions & 2 deletions packages/infinitegrid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"karma-chrome-launcher": "^2.2.0",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.5",
"karma-typescript": "^4.0.0",
"karma-typescript": "^4.0.0",
"karma-viewport": "^1.0.4",
"mocha": "^6.0.2",
"postcss-loader": "^4.1.0",
Expand Down Expand Up @@ -122,7 +122,7 @@
"@cfcs/core": "^0.0.5",
"@egjs/children-differ": "^1.0.1",
"@egjs/component": "^3.0.0",
"@egjs/grid": "~1.12.0",
"@egjs/grid": "^1.13.0",
"@egjs/list-differ": "^1.0.0"
}
}
6 changes: 5 additions & 1 deletion packages/infinitegrid/src/GroupManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Grid, {
GetterSetter,
GridFunction, GridOptions,
GridFunction, GridItem, GridOptions,
GridOutlines, MOUNT_STATE, Properties, PROPERTY_TYPE,
RenderOptions, UPDATE_STATE,
} from "@egjs/grid";
Expand Down Expand Up @@ -547,6 +547,10 @@ export class GroupManager extends Grid<GroupManagerOptions> {
return isRerender;
}

protected _updateItems(items: GridItem[]): void {
this.itemRenderer.updateEqualSizeItems(items, this.groupItems);
}

private _getGroupItems() {
return flatGroups(this.getGroups(true));
}
Expand Down
149 changes: 148 additions & 1 deletion packages/infinitegrid/test/unit/InfiniteGrid.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cleanup, sandbox, waitEvent, waitFor } from "./utils/utils";
import InfiniteGrid from "../../src/InfiniteGrid";
import { SampleGrid } from "./samples/SampleGrid";
import { SampleGrid, SampleGridOptions } from "./samples/SampleGrid";
import { flat, toArray } from "../../src/utils";
import {
InfiniteGridOptions,
Expand Down Expand Up @@ -1570,4 +1570,151 @@ describe("test InfiniteGrid", () => {
expect(ig!.getEndCursor()).to.be.equals(3);
});
});
describe("test size group, equal size", () => {
it("should check if isEqualSize calculates the size of the items in the invisible area.", async () => {
// Given
container!.innerHTML = `<div class="wrapper" style="width: 100%; height: 500px;"></div>`;
const wrapper = container!.querySelector<HTMLElement>(".wrapper")!;

ig = new InfiniteGrid<InfiniteGridOptions & SampleGridOptions>(wrapper, {
gridConstructor: SampleGrid,
container: true,
isEqualSize: true,
injectCSSSize: false,
});

ig!.syncItems([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].map((child) => {
return {
groupKey: Math.floor(child / 3),
key: `key${child}`,
html: `<div style="height: ${100 + child * 10}px;width: 100%;">${child}</div>`,
};
}));

ig!.setCursors(0, 4);
// all cursors
await waitEvent(ig!, "renderComplete");
// partial cursors (0 ~ 2)
await waitEvent(ig!, "renderComplete");

ig!.getScrollContainerElement().scrollTop = 500;
// partial cursors (1 ~ 3)
await waitEvent(ig!, "renderComplete");
// When
// Based on the first item of the currently displayed item, the size of all items is determined to be the same.
ig!.renderItems({
useResize: true,
});

await waitEvent(ig!, "renderComplete");
const visibleItem = ig!.getVisibleItems()[0];

// Then
expect(visibleItem.groupKey).to.be.equals(1);
expect(visibleItem.key).to.be.equals("key3");

ig!.getItems().forEach((item) => {
// The size of all items is the same as the "key3" item
expect(item.rect.height).to.be.equals(130);
});
});
it("should checks if the sizes of the not-equal-size items are different.", async () => {
// Given
container!.innerHTML = `<div class="wrapper" style="width: 100%; height: 500px;"></div>`;
const wrapper = container!.querySelector<HTMLElement>(".wrapper")!;

ig = new InfiniteGrid<InfiniteGridOptions & SampleGridOptions>(wrapper, {
gridConstructor: SampleGrid,
container: true,
isEqualSize: true,
injectCSSSize: false,
});

ig!.syncItems([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].map((child) => {
return {
groupKey: Math.floor(child / 3),
key: `key${child}`,
html: `<div style="height: ${100 + child * 10}px;width: 100%;" ${
child === 7 ? `data-grid-not-equal-size="true"` : ""
}>${child}</div>`,
};
}));

ig!.setCursors(0, 4);
// all cursors
await waitEvent(ig!, "renderComplete");
// partial cursors (0 ~ 2)
await waitEvent(ig!, "renderComplete");

ig!.getScrollContainerElement().scrollTop = 500;
// partial cursors (1 ~ 3)
await waitEvent(ig!, "renderComplete");
// When
// Based on the first item of the currently displayed item, the size of all items is determined to be the same.
ig!.renderItems({
useResize: true,
});

await waitEvent(ig!, "renderComplete");
// Then
ig!.getItems().forEach((item, i) => {
// Except for item 7, all are the same size (130).
if (i === 7) {
expect(ig!.getItems()[7].rect.height).to.be.equals(170);
} else {
// The size of all items is the same as the "key3" item
expect(item.rect.height).to.be.equals(130);
}
});
});
it("should check if size group calculates the size of the group of items in the invisible area.", async () => {
// Given
container!.innerHTML = `<div class="wrapper" style="width: 100%; height: 500px;"></div>`;
const wrapper = container!.querySelector<HTMLElement>(".wrapper")!;

ig = new InfiniteGrid<InfiniteGridOptions & SampleGridOptions>(wrapper, {
gridConstructor: SampleGrid,
container: true,
injectCSSSize: false,
});

ig!.syncItems([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].map((child) => {
return {
groupKey: Math.floor(child / 3),
key: `key${child}`,
html: `<div style="height: ${100 + child * 10}px;width: 100%;" data-grid-size-group="${child % 2}">${child}</div>`,
};
}));

ig!.setCursors(0, 4);
// all cursors
await waitEvent(ig!, "renderComplete");
// partial cursors (0 ~ 2)
await waitEvent(ig!, "renderComplete");

ig!.getScrollContainerElement().scrollTop = 500;
// partial cursors (1 ~ 3)
await waitEvent(ig!, "renderComplete");
// When
// Based on the first item of the currently displayed item, the size of all items is determined to be the same.
ig!.renderItems({
useResize: true,
});

await waitEvent(ig!, "renderComplete");
const [item1, item2] = ig!.getVisibleItems();

// Then
expect(item1.key).to.be.equals("key3");
expect(item2.key).to.be.equals("key4");
expect(item1.rect.height).to.be.equals(130);
expect(item2.rect.height).to.be.equals(140);

// The size of all items (even "0") is the same as the "key4" item
// The size of all items (odd, "1") is the same as the "key3" item
ig!.getItems().forEach((item, i) => {
expect(item.rect.height).to.be.equals(i % 2 ? 130 : 140);
});
});
});
});
44 changes: 30 additions & 14 deletions packages/infinitegrid/test/unit/samples/SampleGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Grid, {
export interface SampleGridOptions extends GridOptions {
renderProperty?: number;
property?: string;
injectCSSSize?: boolean;
}

@GetterSetter
Expand All @@ -17,11 +18,13 @@ export class SampleGrid extends Grid<SampleGridOptions> {
...Grid.propertyTypes,
renderProperty: PROPERTY_TYPE.RENDER_PROPERTY,
property: PROPERTY_TYPE.PROPERTY,
injectCSSSize: PROPERTY_TYPE.PROPERTY,
};
public static defaultOptions: Required<SampleGridOptions> = {
...Grid.defaultOptions,
renderProperty: -1,
property: "property1",
injectCSSSize: true,
};

public applyGrid(items: GridItem[], direction: "start" | "end", outline: number[]) {
Expand All @@ -33,13 +36,19 @@ export class SampleGrid extends Grid<SampleGridOptions> {
const prevPos = endOutline[0] || 0;
const rect = item.rect;


item.setCSSGridRect({
inlineSize: item.inlineSize,
contentSize: item.contentSize,
contentPos: prevPos,
inlinePos: 0,
});
if (this.injectCSSSize) {
item.setCSSGridRect({
inlineSize: item.inlineSize,
contentSize: item.contentSize,
contentPos: prevPos,
inlinePos: 0,
});
} else {
item.setCSSGridRect({
contentPos: prevPos,
inlinePos: 0,
});
}

endOutline = [prevPos + (rect?.height ?? 0) + this.gap];
});
Expand All @@ -49,13 +58,20 @@ export class SampleGrid extends Grid<SampleGridOptions> {
const rect = item.rect;

startOutline = [prevPos - (rect?.height ?? 0) - this.gap];

item.setCSSGridRect({
inlineSize: item.inlineSize,
contentSize: item.contentSize,
contentPos: startOutline[0],
inlinePos: 0,
});

if (this.injectCSSSize) {
item.setCSSGridRect({
inlineSize: item.inlineSize,
contentSize: item.contentSize,
contentPos: startOutline[0],
inlinePos: 0,
});
} else {
item.setCSSGridRect({
contentPos: startOutline[0],
inlinePos: 0,
});
}
});
}
return {
Expand Down
19 changes: 14 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2478,10 +2478,10 @@
"@egjs/imready" "^1.1.3"
"@egjs/list-differ" "^1.0.0"

"@egjs/grid@~1.12.0":
version "1.12.0"
resolved "https://registry.npmjs.org/@egjs/grid/-/grid-1.12.0.tgz#0e83eb20ecc43e149f4d144bab84d23fbc9687df"
integrity sha512-LKUgbDE0Dr1Nq2V+DPrf3CNaQb/f3ELFX9V+23QlBxBdvcb7HqnywNjDfUoQ7fEdyiTfIg55r9vHl8v9B/WXJw==
"@egjs/grid@^1.13.0":
version "1.13.0"
resolved "https://registry.npmjs.org/@egjs/grid/-/grid-1.13.0.tgz#8298a9464afbcd44a6738b190e00c22313340b37"
integrity sha512-wUljkpteE6THydxBvIPcXKQWx4PUo+BCOoRnq1R0cF/pauYQKMEEuzZfMzI6NpjNBtfC3SzdXANeJYtq01cSkg==
dependencies:
"@egjs/children-differ" "^1.0.1"
"@egjs/component" "^3.0.0"
Expand Down Expand Up @@ -24928,7 +24928,16 @@ read@1, read@~1.0.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"

"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
"readable-stream@2 || 3":
version "3.6.2"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"

readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
Expand Down

0 comments on commit f693db9

Please sign in to comment.