@thi.ng/layout
Version:
Configurable nested 2D grid layout generators
99 lines (98 loc) • 2.38 kB
JavaScript
import { isNumber } from "@thi.ng/checks/is-number";
const __DEFAULT_SPANS = [1, 1];
class GridLayout {
parent;
cols;
width;
x;
y;
cellW;
cellH;
cellWG;
cellHG;
gap;
currCol;
currRow;
rows;
constructor(parent, x, y, width, cols, rowH, gap) {
this.parent = parent;
this.cols = cols;
this.x = x;
this.y = y;
this.width = width;
this.cellW = (width - (cols - 1) * gap) / cols;
this.cellH = rowH;
this.cellWG = this.cellW + gap;
this.cellHG = rowH + gap;
this.gap = gap;
this.currCol = 0;
this.currRow = 0;
this.rows = 0;
}
colsForWidth(w) {
return Math.ceil(w / this.cellWG);
}
rowsForHeight(h) {
return Math.ceil(h / this.cellHG);
}
spanForSize(w, h) {
const size = isNumber(w) ? [w, h] : w;
return [this.colsForWidth(size[0]), this.rowsForHeight(size[1])];
}
next(spans = __DEFAULT_SPANS) {
const { cellWG, cellHG, gap, cols } = this;
const cspan = Math.min(spans[0], cols);
const rspan = spans[1];
if (this.currCol > 0) {
if (this.currCol + cspan > cols) {
this.currCol = 0;
this.currRow = this.rows;
}
} else {
this.currRow = this.rows;
}
const h = rspan * cellHG - gap;
const cell = {
x: this.x + this.currCol * cellWG,
y: this.y + this.currRow * cellHG,
w: cspan * cellWG - gap,
h,
cw: this.cellW,
ch: this.cellH,
gap,
span: [cspan, rspan]
};
this.propagateSize(rspan);
this.currCol = Math.min(this.currCol + cspan, cols) % cols;
return cell;
}
// TODO add optional colspan arg, fix rounding
nextSquare() {
const box = this.next([
1,
Math.ceil(this.cellW / (this.cellH + this.gap)) + 1
]);
box.h = box.w;
return box;
}
nest(cols, spans, gap = this.gap) {
const { x, y, w } = this.next(spans);
return new GridLayout(this, x, y, w, cols, this.cellH, gap);
}
/**
* Updates max rows used in this layout and all of its parents.
*
* @param rspan -
*/
propagateSize(rspan) {
let rows = this.rows;
this.rows = rows = Math.max(rows, this.currRow + rspan);
this.parent?.propagateSize(rows);
}
}
const gridLayout = (x, y, width, cols = 1, rowH = 16, gap = 4) => new GridLayout(null, x, y, width, cols, rowH, gap);
export {
GridLayout,
__DEFAULT_SPANS,
gridLayout
};