import { WindowInfo, WindowId } from "./types"; interface NewGraph { [key: string]: { above: string[]; left: string[]; }; } interface PositionDiff { [key: string]: { x: number; y: number; }; } export interface SizeDiff { [key: string]: { width: number; height: number; }; } export function getPositionDiff( graph: Graph, sizeDiff: SizeDiff ): PositionDiff { const newGraph: NewGraph = {}; const positionDiff: PositionDiff = {}; for (const key of Object.keys(graph)) { newGraph[key] = { above: [], left: [] }; positionDiff[key] = { x: 0, y: 0 }; } // Construct an inverted graph for (const [key, neighbors] of Object.entries(graph)) { const { below, right } = neighbors; if (right != null) { newGraph[right].left.push(key); } if (below != null) { newGraph[below].above.push(key); } } function walkRight(key: WindowId) { const node = newGraph[key]; const nodeSizeDiff = sizeDiff[key]; node.left.forEach(left => { positionDiff[left].x += nodeSizeDiff.width + positionDiff[key].x; walkRight(left); }); } function walkDown(key: WindowId) { const node = newGraph[key]; const nodeSizeDiff = sizeDiff[key]; node.above.forEach(above => { positionDiff[above].y += nodeSizeDiff.height + positionDiff[key].y; walkDown(above); }); } // Find disconnected nodes, and walk for (const [key, neighbors] of Object.entries(graph)) { if (neighbors.below == null) { walkDown(key); } if (neighbors.right == null) { walkRight(key); } } return positionDiff; } interface Edges { below?: WindowId; right?: WindowId; } interface Graph { // TODO: Ensure this is a WindowId [id: string]: Edges; } export function generateGraph(windows: WindowInfo[]): Graph { const bottoms: { [offset: number]: WindowInfo[] } = {}; const rights: { [offset: number]: WindowInfo[] } = {}; for (const w of windows) { const bottom = w.y + w.height; if (bottoms[bottom]) { bottoms[bottom].push(w); } else { bottoms[bottom] = [w]; } const right = w.x + w.width; if (rights[right]) { rights[right].push(w); } else { rights[right] = [w]; } } const graph: Graph = {}; for (const w of windows) { const edges: Edges = {}; const top = w.y; const left = w.x; const tops = bottoms[top]; const lefts = rights[left]; if (tops) { for (const below of tops) { const isToTheLeft = below.x + below.width < w.x; const isToTheRight = below.x > w.x + w.width; const overlapsInX = !(isToTheLeft || isToTheRight); if (overlapsInX) { edges.below = below.key; break; } } } if (lefts) { for (const right of lefts) { const isAbove = right.y + right.height < w.y; const isBelow = right.y > w.y + w.height; const overlapsInY = !(isAbove || isBelow); if (overlapsInY) { edges.right = right.key; break; } } } graph[w.key] = edges; } return graph; }