UNPKG

@thi.ng/layout

Version:

Configurable nested 2D grid layout generators

99 lines (98 loc) 2.38 kB
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 };