Skip to content

Commit

Permalink
Better grid algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
samwho committed Oct 28, 2023
1 parent d00fdf3 commit 0755047
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 14 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pixijs-layout",
"version": "0.1.12",
"version": "0.1.13",
"description": "",
"main": "./out/index.js",
"types": "./out/index.d.ts",
Expand Down
Binary file modified screenshots/8-item-grid-circles-fit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/8-item-grid-circles-stretch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 52 additions & 3 deletions src/Grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,73 @@ export function Grid(...objects: DisplayObject[]): GridComponent {
}

export class GridComponent extends Partitioner {
_centerLastRow: boolean = false;

constructor(...children: DisplayObject[]) {
super(...children);
}

centerLastRow(): GridComponent {
this._centerLastRow = true;
return this;
}

_rowsCols(n: number): number {
for (let i = Math.ceil(Math.sqrt(n)); i >= 1; i--) {
if (n % i === 0) {
return i;
}
}
return 1;
}

*partition(objects: DisplayObject[], space: Rectangle): Generator<Rectangle> {
let containers = objects as Container[];

let factors = [];
for (let i = 1; i <= Math.sqrt(containers.length); i++) {
if (containers.length % i === 0) {
factors.push(i, containers.length / i);
}
}
factors = [...new Set(factors)].sort((a, b) => a - b);

let aspectRatio = space.width / space.height;
let rows = Math.ceil(Math.sqrt(containers.length / aspectRatio));
let columns = Math.ceil(containers.length / rows);
let bestDiff = Infinity;
let rows, columns;
for (let factor of factors) {
let possibleRows = factor;
let possibleCols = containers.length / possibleRows;
let diff = Math.abs(aspectRatio - possibleCols / possibleRows);
if (diff < bestDiff) {
bestDiff = diff;
rows = possibleRows;
columns = possibleCols;
}
}

if (!rows || !columns) {
rows = Math.ceil(Math.sqrt(containers.length / aspectRatio));
columns = Math.ceil(containers.length / rows);
}

let width = space.width / columns;
let height = space.height / rows;

let row = 0;
let column = 0;
for (let _ of containers) {
let shift = 0;
if (
this._centerLastRow &&
row === rows - 1 &&
columns * rows > containers.length
) {
shift = ((columns * rows - containers.length) * width) / 2;
}

let partition = new Rectangle(
space.x + column * width,
space.x + column * width + shift,
space.y + row * height,
width,
height,
Expand Down
11 changes: 1 addition & 10 deletions src/Partitioner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ export default abstract class Partitioner
.reduce((a, b) => Math.min(a, b), Infinity);
}

private _isContainer(obj: DisplayObject): obj is Container {
// For whatever reason, when I do `obj instanceof Container`, it returns
// true in my tests but false when I import this library into another
// project. I spent time looking into it and concluded that there seemed
// to be 2 instances of pixi.js classes being loaded, one from .js files
// and the other from .mjs files. I never got to the bottom of this.
return "width" in obj && "height" in obj;
}

leaves(fn: (l: LeafComponent) => LeafComponent): this {
let i = 0;
for (let _ of this._group) {
Expand All @@ -36,7 +27,7 @@ export default abstract class Partitioner
child.leaves(fn);
} else if (child instanceof LeafComponent) {
this._group[i] = fn(child);
} else if (this._isContainer(child)) {
} else if (child instanceof Container) {
this._group[i] = fn(Leaf(child));
}
i += 1;
Expand Down

0 comments on commit 0755047

Please sign in to comment.