webamp/js/resizeUtils.ts

141 lines
3.1 KiB
TypeScript

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;
}