grid.mjs
62 lines · archify/renderers/architecture/grid.mjs at a406594
1/** Grid placement for architecture IR (#8). Not auto-layout — fixed cell math only. */
3export const DEFAULT_GRID = {
4 mode: 'grid',
5 origin: [40, 80],
6 cols: 4,
7 gapX: 30,
8 gapY: 40,
9 cellW: 130,
10 cellH: 64,
11};
13export function gridLayout(arch) {
14 const raw = arch.layout;
15 if (!raw || raw.mode !== 'grid') return null;
16 return { ...DEFAULT_GRID, ...raw };
17}
19export function resolveComponentPos(component, grid) {
20 if (Array.isArray(component.pos) && component.pos.length === 2) {
21 return component.pos;
22 }
23 if (!grid) return [NaN, NaN];
24 if (!Number.isInteger(component.row) || !Number.isInteger(component.col)) {
25 return [NaN, NaN];
26 }
27 const [ox, oy] = grid.origin;
28 const stepX = grid.cellW + grid.gapX;
29 const stepY = grid.cellH + grid.gapY;
30 return [ox + component.col * stepX, oy + component.row * stepY];
31}
33export function validateGridPlacement(arch, grid, problems) {
34 if (!grid) return;
35 if (arch.layout !== undefined && arch.layout.mode !== 'grid') {
36 problems.push('layout.mode must be "grid" when layout is set (free placement omits layout entirely).');
37 return;
38 }
39 const seen = new Map();
40 for (const c of arch.components ?? []) {
41 const hasPos = Array.isArray(c.pos) && c.pos.length === 2;
42 const hasCell = Number.isInteger(c.row) && Number.isInteger(c.col);
43 if (hasPos) continue; // pos wins; row/col are optional hints only
44 if (!hasPos && !hasCell) {
45 problems.push(`Component "${c.id}" needs pos [x,y] or grid row/col when layout.mode is "grid".`);
46 continue;
47 }
48 if (c.row < 0 || c.col < 0) {
49 problems.push(`Component "${c.id}" row/col must be non-negative integers.`);
50 continue;
51 }
52 if (c.col >= grid.cols) {
53 problems.push(`Component "${c.id}" col ${c.col} exceeds layout.cols ${grid.cols} (valid: 0..${grid.cols - 1}).`);
54 }
55 const key = `${c.row},${c.col}`;
56 if (seen.has(key)) {
57 problems.push(`Components "${seen.get(key)}" and "${c.id}" share grid cell row ${c.row} col ${c.col}.`);
58 } else {
59 seen.set(key, c.id);
60 }
61 }
62}