Skip to content

feat(er-diagram): lay tables out in compact 2D clusters with color#1757

Merged
datlechin merged 6 commits into
mainfrom
emdash/feat-er-diagram-layout-problem-database-1335-s1ntm
Jun 23, 2026
Merged

feat(er-diagram): lay tables out in compact 2D clusters with color#1757
datlechin merged 6 commits into
mainfrom
emdash/feat-er-diagram-layout-problem-database-1335-s1ntm

Conversation

@datlechin

Copy link
Copy Markdown
Member

Closes #1755 (related #1335)

Problem

The ER diagram used a Sugiyama layered layout that ranked tables into horizontal rows by foreign-key depth, then centered every row inside the combined width of all nodes. Shallow, cyclic schemas collapsed into a few very wide rows stacked vertically, so large diagrams were tall, narrow, and wasted horizontal space.

Change

Replaced the layered engine with a component-aware compact layout, and reused the connected-component pass to color clusters.

  • Detect connected components of the FK graph with union-find. Components of two or more tables get a stable cluster id (ordered by minimum table name, so it survives reconnects). Single tables and tables with no foreign keys stay uncolored.
  • Lay out each component with a force-directed pass (Fruchterman-Reingold, node-size aware, deterministic circular init so layouts reproduce, iteration count capped by component size), remove residual box overlaps, then bin-pack the component blocks into 2D so the diagram fills both axes. Isolated tables sit in a grid at the bottom.
  • Tint each connected group's header with its own color from a palette of named system colors (they adapt to light/dark and Increase Contrast). When the system Differentiate Without Color setting is on, the tint is dropped so grouping never relies on color alone. Applied to the live canvas and the PNG export.

ERDiagramLayout.compute keeps its signature (graph -> [UUID: CGPoint]), so the ViewModel, persistence, and re-layout paths are unchanged.

Tests

The graph/layout pipeline had no coverage. Added:

  • ERClusterAnalyzerTests: chain, star, two components, isolated tables, self-loop, mixed, determinism, empty.
  • ERDiagramLayoutTests: every node positioned, no box overlap, components in disjoint regions, deterministic re-run, isolated tables fill horizontal space, empty/single graph.

Notes

  • Scope is layout + automatic grouping/coloring. No manual group-editing UI and no edge coloring.
  • Docs (docs/features/er-diagram.mdx) and CHANGELOG.md updated.
  • swiftlint lint --strict clean on all changed files. Build/run not done locally (Xcode build is the maintainer's step).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0e6077387

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

let totalArea = blockSizes.reduce(0) { $0 + $1.width * $1.height }
let widest = blockSizes.map(\.width).max() ?? 0
let targetWidth = max(widest, sqrt(totalArea * 1.6))
let order = blockSizes.indices.sorted { blockSizes[$0].height > blockSizes[$1].height }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep isolated tables below relationship groups

When a schema has many unrelated tables plus a small FK component, the unrelated-table grid is usually the tallest block, so this height sort places it at (0,0) and shelves the connected component below it. That contradicts the new layout behavior documented in docs/features/er-diagram.mdx:25 that tables with no relationships sit at the bottom, and it makes the main relationship diagram start underneath unrelated noise. Keep the singleton grid out of this height-based ordering or force it to be packed after connected components.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1614e2bee2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

) {
let count = members.count
let padding = horizontalGap * 0.5
let passes = max(20, min(count, 60))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guarantee overlap removal for dense components

For dense relationship components (for example, a few dozen tables with several FKs per table), this fixed pass limit can exit while table rectangles still intersect; there is no validation after removeOverlaps, so makeBlock and the Canvas render those tables on top of each other. Please keep resolving until there are no collisions, or fall back to a grid/packing strategy when the limit is reached.

Useful? React with 👍 / 👎.

@mintlify

mintlify Bot commented Jun 22, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jun 22, 2026, 7:05 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@datlechin datlechin merged commit 6b54823 into main Jun 23, 2026
2 of 3 checks passed
@datlechin datlechin deleted the emdash/feat-er-diagram-layout-problem-database-1335-s1ntm branch June 23, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(er-diagram): improve diagram layout

1 participant