Skip to content

fix: tighten chrome-to-legend gap and y-axis title clearance#77

Merged
rileyhilliard merged 2 commits into
mainfrom
fix/layout-spacing-polish
Jun 3, 2026
Merged

fix: tighten chrome-to-legend gap and y-axis title clearance#77
rileyhilliard merged 2 commits into
mainfrom
fix/layout-spacing-polish

Conversation

@rileyhilliard
Copy link
Copy Markdown
Member

@rileyhilliard rileyhilliard commented Jun 3, 2026

Summary

  • Reduces excessive vertical space between chrome/subtitle and chart area when a top legend is present by not doubling axisMargin with legendGap
  • Increases y-axis title clearance from ~1px to ~7px by bumping AXIS_TITLE_GAP from 8 to 14
  • Fixes renderer/dimensions.ts mismatch where renderer used hardcoded AXIS_TITLE_OFFSET_COMPACT while dimensions.ts used width-aware getAxisTitleOffset()

Test plan

  • 3 new regression tests in dimensions.test.ts covering both fixes
  • Full test suite passes (2141 tests)
  • Typecheck + biome lint pass
  • Visual QA on charts with top legends (should have tighter chrome-to-chart spacing)
  • Visual QA on charts with y-axis titles (title text should have breathing room from tick labels)

Summary by CodeRabbit

  • Bug Fixes

    • Fixed spacing calculation errors in charts with top legends that created redundant gaps and reduced available chart area.
  • Improvements

    • Enhanced y-axis title spacing and positioning to better accommodate varying label widths and improve overall chart layout clarity.

Two layout spacing fixes:

1. Top legend gap: when a top legend is present, legendGap already separates
   it from what's above, so adding the full topAxisGap (axisMargin +
   inlineTickOverhang) created redundant spacing. Now only adds
   inlineTickOverhang when a top legend exists.

2. Y-axis title cramping: AXIS_TITLE_GAP (distance from tick label edge to
   title center) was 8px, but the rotated glyph extends ~7px from center,
   leaving only 1px visual clearance. Bumped to 14px for ~7px breathing room.
   Also fixed renderer using hardcoded AXIS_TITLE_OFFSET_COMPACT floor
   instead of width-aware getAxisTitleOffset() that dimensions.ts uses.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Warning

Review limit reached

@rileyhilliard, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 35 minutes and 31 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f0a30054-f53a-45c2-8ab1-c468c66ae726

📥 Commits

Reviewing files that changed from the base of the PR and between d76c377 and eec6bc0.

📒 Files selected for processing (5)
  • packages/core/src/index.ts
  • packages/core/src/responsive/index.ts
  • packages/core/src/responsive/metrics.ts
  • packages/engine/src/layout/dimensions.ts
  • packages/vanilla/src/renderers/axes.ts
📝 Walkthrough

Walkthrough

This PR refines chart layout spacing by increasing the y-axis title gap constant from 8 to 14 pixels across the dimensions engine and renderer, and fixes top legend margin calculation to prevent double-counting spacing by using inlineTickOverhang when a top legend is present instead of always applying the full topAxisGap.

Changes

Chart Dimension and Axis Layout Spacing

Layer / File(s) Summary
Y-axis title spacing constant and offset updates
packages/engine/src/layout/dimensions.ts, packages/vanilla/src/renderers/axes.ts, packages/engine/src/__tests__/dimensions.test.ts
AXIS_TITLE_GAP increases from 8 to 14 in both the dimensions engine and axes renderer. The renderer now clamps the y-axis rotated title offset using width-based getAxisTitleOffset() instead of a fixed compact constant. Tests verify that left margin grows when a y-axis title is present and scales with wider tick label text.
Top legend spacing detection and margin adjustment
packages/engine/src/layout/dimensions.ts, packages/engine/src/__tests__/dimensions.test.ts
A hasTopLegend flag detects top legend presence. When true, margins.top uses only inlineTickOverhang instead of the full topAxisGap to avoid redundant spacing. A regression test confirms this adjustment eliminates spacing double-counting while still reducing chart area height relative to the no-legend case.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A rabbit hops through spacing rules so tight,
Y-axis titles now have proper height,
Top legends dance without a double share,
Margins breathing room with loving care! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main changes: tightening chrome-to-legend gap and improving y-axis title clearance, matching the core objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/layout-spacing-polish

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/engine/src/layout/dimensions.ts (1)

638-640: ⚡ Quick win

Consider sharing AXIS_TITLE_GAP with the renderer.

This AXIS_TITLE_GAP = 14 is now duplicated as a local literal here and in packages/vanilla/src/renderers/axes.ts (Line 275). The reservation here only matches the renderer's placement as long as both literals stay in sync; a future edit to one will silently reintroduce the renderer/dimensions mismatch this PR set out to fix. Exporting a single constant from @opendata-ai/openchart-core (alongside TICK_LABEL_OFFSET / getAxisTitleOffset) would keep them locked together.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/layout/dimensions.ts` around lines 638 - 640, The literal
AXIS_TITLE_GAP = 14 is duplicated and should be centralized; instead of
hardcoding it in packages/engine/src/layout/dimensions.ts, export a single
AXIS_TITLE_GAP constant from the core module alongside TICK_LABEL_OFFSET and
getAxisTitleOffset, then import and use that exported AXIS_TITLE_GAP in
dimensions.ts (where dynamicTitleOffset is computed) and in
packages/vanilla/src/renderers/axes.ts so both renderer and layout share the
same authoritative value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/engine/src/__tests__/dimensions.test.ts`:
- Around line 487-488: The test's threshold is too loose; update the assertion
for topMarginDelta (comparing dimsWithTopLegend and dimsNoLegend) to use the
correct smaller allowance by replacing the current bound
(topLegend.bounds.height + legendGap(600) + 1) with topLegend.bounds.height +
legendGap(600) + inlineTickOverhang (i.e., the inline tick overhang, not the
full topAxisGap) so the correct delta (~30) passes but the doubled bug (~36)
fails; look for dimsWithTopLegend, dimsNoLegend, topLegend, legendGap, and
inlineTickOverhang and the related logic modified around dimensions.ts (near the
change at line 679) to make this assertion precise.

---

Nitpick comments:
In `@packages/engine/src/layout/dimensions.ts`:
- Around line 638-640: The literal AXIS_TITLE_GAP = 14 is duplicated and should
be centralized; instead of hardcoding it in
packages/engine/src/layout/dimensions.ts, export a single AXIS_TITLE_GAP
constant from the core module alongside TICK_LABEL_OFFSET and
getAxisTitleOffset, then import and use that exported AXIS_TITLE_GAP in
dimensions.ts (where dynamicTitleOffset is computed) and in
packages/vanilla/src/renderers/axes.ts so both renderer and layout share the
same authoritative value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b4b1981-3f14-419a-bbdb-240ceb62499a

📥 Commits

Reviewing files that changed from the base of the PR and between b5ffbba and d76c377.

📒 Files selected for processing (3)
  • packages/engine/src/__tests__/dimensions.test.ts
  • packages/engine/src/layout/dimensions.ts
  • packages/vanilla/src/renderers/axes.ts

Comment on lines +487 to +488
const topMarginDelta = dimsWithTopLegend.margins.top - dimsNoLegend.margins.top;
expect(topMarginDelta).toBeLessThan(topLegend.bounds.height + legendGap(600) + 1);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

This regression assertion is too loose to catch the bug it guards.

The comment shows the correct delta is 30 and the doubling-bug delta is 36, but the threshold is topLegend.bounds.height + legendGap(600) + 1 = 28 + 8 + 1 = 37. Both 30 < 37 and 36 < 37 pass, so reverting the fix (adding the full topAxisGap instead of inlineTickOverhang at dimensions.ts Line 679) would not fail this test. Tighten the bound so the doubling case (36) is excluded.

💚 Proposed tighter bound
-    const topMarginDelta = dimsWithTopLegend.margins.top - dimsNoLegend.margins.top;
-    expect(topMarginDelta).toBeLessThan(topLegend.bounds.height + legendGap(600) + 1);
+    const topMarginDelta = dimsWithTopLegend.margins.top - dimsNoLegend.margins.top;
+    // Doubling would add the full topAxisGap (= axisMargin + inlineTickOverhang)
+    // on top of legendHeight + legendGap; the correct path adds only
+    // inlineTickOverhang, so the delta must stay strictly below height + gap.
+    expect(topMarginDelta).toBeLessThan(topLegend.bounds.height + legendGap(600));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const topMarginDelta = dimsWithTopLegend.margins.top - dimsNoLegend.margins.top;
expect(topMarginDelta).toBeLessThan(topLegend.bounds.height + legendGap(600) + 1);
const topMarginDelta = dimsWithTopLegend.margins.top - dimsNoLegend.margins.top;
// Doubling would add the full topAxisGap (= axisMargin + inlineTickOverhang)
// on top of legendHeight + legendGap; the correct path adds only
// inlineTickOverhang, so the delta must stay strictly below height + gap.
expect(topMarginDelta).toBeLessThan(topLegend.bounds.height + legendGap(600));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/__tests__/dimensions.test.ts` around lines 487 - 488, The
test's threshold is too loose; update the assertion for topMarginDelta
(comparing dimsWithTopLegend and dimsNoLegend) to use the correct smaller
allowance by replacing the current bound (topLegend.bounds.height +
legendGap(600) + 1) with topLegend.bounds.height + legendGap(600) +
inlineTickOverhang (i.e., the inline tick overhang, not the full topAxisGap) so
the correct delta (~30) passes but the doubled bug (~36) fails; look for
dimsWithTopLegend, dimsNoLegend, topLegend, legendGap, and inlineTickOverhang
and the related logic modified around dimensions.ts (near the change at line
679) to make this assertion precise.

Move AXIS_TITLE_GAP from duplicated local consts in dimensions.ts and
axes.ts to a single export in core/responsive/metrics.ts. Fixes the
same desync pattern (renderer vs engine using different values) that
the prior commit corrected for AXIS_TITLE_OFFSET_COMPACT.

Also fixes the stale comment in dimensions.ts that still referenced
the old 8px gap and AXIS_TITLE_OFFSET_COMPACT.
@rileyhilliard rileyhilliard merged commit 8d81359 into main Jun 3, 2026
1 check was pending
@rileyhilliard rileyhilliard deleted the fix/layout-spacing-polish branch June 3, 2026 19:42
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.

1 participant