Skip to content

feat(component): auto-rotate and truncate axis labels - #171

Closed
alfredo1996 wants to merge 3 commits into
devfrom
feat/issue-137-axis-labels
Closed

feat(component): auto-rotate and truncate axis labels#171
alfredo1996 wants to merge 3 commits into
devfrom
feat/issue-137-axis-labels

Conversation

@alfredo1996

@alfredo1996 alfredo1996 commented Mar 22, 2026

Copy link
Copy Markdown
Owner

Summary

Auto-rotate and truncate category axis labels for the bar chart when there are many categories. Prevents overlapping labels and improves readability for large datasets.

Changes

  • New: buildCategoryAxisLabel() in chart-utils.ts — auto-rotation (30° at 8+, 45° at 15+ categories), truncation (>15 chars → ellipsis), tooltip for full text
  • Updated: BarChart — uses the new utility, new axisLabelRotation prop
  • Updated: chart-options-schema.ts — "Axis Label Rotation" option for bar chart (-1 = auto)
  • 9 new tests for the label utility

Test plan

  • cd component && npm test — 68 suites, 1018 tests
  • cd app && npm test — 72 suites, 1260 tests
  • Build + lint clean

Closes #137

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • New bar-chart option to override axis label rotation; automatic rotation applied by category count (0°, 30°, 45°). Long labels are truncated with ellipsis; hover tooltips show full text and are hidden in compact mode.
    • Improved rendering support for mark lines and custom graphics in charts.
  • Tests

    • Added tests validating axis label rotation behavior, truncation/ellipsis, tooltip visibility, and compact-mode handling.

Add buildCategoryAxisLabel() utility to chart-utils.ts:
- Auto-rotate 30° at 8+ categories, 45° at 15+
- Truncate labels >15 chars with ellipsis (U+2026)
- Tooltip shows full text on hover
- Configurable rotation override via chart option

Wire into BarChart component with axisLabelRotation prop.
Add "Axis Label Rotation" option to chart-options-schema.

Closes #137

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alfredo1996 alfredo1996 added enhancement New feature or request pkg:component UI component library area:charts Chart rendering labels Mar 22, 2026
@coderabbitai

coderabbitai Bot commented Mar 22, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 43b646a9-5641-4e86-9d2d-a5861d30f8b9

📥 Commits

Reviewing files that changed from the base of the PR and between b826fac and 6c2eab5.

📒 Files selected for processing (5)
  • component/src/charts/__tests__/axis-label-utils.test.ts
  • component/src/charts/__tests__/base-chart.test.tsx
  • component/src/charts/base-chart.tsx
  • component/src/charts/chart-utils.ts
  • component/vitest.setup.ts
✅ Files skipped from review due to trivial changes (2)
  • component/src/charts/tests/base-chart.test.tsx
  • component/vitest.setup.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • component/src/charts/tests/axis-label-utils.test.ts
  • component/src/charts/chart-utils.ts

Walkthrough

Adds automatic rotation and truncation for category axis labels and exposes an optional axisLabelRotation override. Introduces buildCategoryAxisLabel(...) to compute rotation, truncation/formatter, visibility, and tooltip config; integrates it into BarChart and adds tests and an options schema entry.

Changes

Cohort / File(s) Summary
Axis Label Utilities
component/src/charts/chart-utils.ts
New CategoryAxisLabelOptions/CategoryAxisLabelConfig types and exported buildCategoryAxisLabel(categoryCount, options?). Determines rotate (auto 0°/30°/45° with -1 treated as automatic), adds truncation formatter with ellipsis for long labels (default max 15), sets show: !compact, and includes tooltip: { show: true }.
Bar Chart Integration
component/src/charts/bar-chart.tsx
Added optional prop axisLabelRotation?: number. Category axis now derives labels from categoryLabels, calls buildCategoryAxisLabel(...) (passes compact and override), uses returned axisLabelConfig in axis, sets axisPointer: { type: "shadow" }, and conditions nameGap on rotation. Updated useMemo deps.
Tests
component/src/charts/__tests__/axis-label-utils.test.ts, component/src/charts/__tests__/base-chart.test.tsx, component/vitest.setup.ts
Added Vitest tests for buildCategoryAxisLabel covering rotation heuristics, truncation/ellipsis, maxLabelLength override, rotateOverride (including 0 and -1 sentinel), tooltip show behavior and compact handling. Added mocks for MarkLineComponent and GraphicComponent.
Chart Options Schema
component/src/components/composed/chart-options-schema.ts
Registered new bar-chart option axisLabelRotation (type number, default -1) so UI/configuration can override automatic rotation.
ECharts Registration
component/src/charts/base-chart.tsx
Imported and registered additional ECharts components: MarkLineComponent and GraphicComponent.

Sequence Diagram(s)

sequenceDiagram
    participant BarChart as BarChart (component)
    participant Utils as buildCategoryAxisLabel()
    participant ECharts as ECharts (renderer)
    participant User as User (hover)

    BarChart->>Utils: compute axisLabelConfig(categoryCount, { compact?, rotateOverride?, maxLabelLength? })
    Utils-->>BarChart: axisLabelConfig { rotate, formatter?, show, tooltip:{show} }
    BarChart->>ECharts: render chart with category axis using axisLabelConfig
    User->>ECharts: hover truncated label
    ECharts-->>User: show tooltip (full label) per axisLabelConfig.tooltip
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature: auto-rotation and truncation of axis labels.
Linked Issues check ✅ Passed All objectives from #137 are met: auto-rotation at 8+/15+ categories, label truncation with ellipsis, hover tooltip, and configurable rotation override.
Out of Scope Changes check ✅ Passed All changes are in-scope. ECharts component mocks (MarkLine, Graphic) are required test infrastructure supporting the label rendering feature.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 feat/issue-137-axis-labels

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
component/src/charts/chart-utils.ts (1)

40-49: Consider handling -1 sentinel within the utility for defensive programming.

The utility accepts any rotateOverride value without validation. While the immediate fix should be in bar-chart.tsx, making the utility defensive against the -1 sentinel (and potentially other invalid values) would prevent future misuse.

♻️ Optional defensive enhancement
   let rotate: number;
-  if (rotateOverride !== undefined) {
+  if (rotateOverride !== undefined && rotateOverride >= 0) {
     rotate = rotateOverride;
   } else if (categoryCount >= 15) {

This treats any negative value as "use automatic", which aligns with the documented behavior (0-90 valid range).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@component/src/charts/chart-utils.ts` around lines 40 - 49, Update the
rotation selection logic to treat negative rotateOverride values (e.g., -1
sentinel) as "automatic" rather than a literal override: when determining rotate
(using the rotateOverride and categoryCount variables), only accept
rotateOverride if it is defined and within the valid 0–90 range; if
rotateOverride is undefined or negative (or out of range) fall back to the
categoryCount heuristics (categoryCount >= 15 => 45, >= 8 => 30, else 0). Ensure
this defensive check is applied where rotate and rotateOverride are used so
future callers cannot force invalid rotations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@component/src/charts/__tests__/axis-label-utils.test.ts`:
- Around line 36-44: Add a test that verifies rotateOverride: -1 is treated as
the "automatic" sentinel and not used as a negative angle: update the tests for
buildCategoryAxisLabel to include a case (e.g., it("treats -1 rotateOverride as
automatic", ...)) that calls buildCategoryAxisLabel(20, { rotateOverride: -1 })
and asserts result.rotate equals the automatic angle (45 for 20 categories);
ensure the test references buildCategoryAxisLabel and rotateOverride so behavior
is documented and prevents returning -1 as the angle.

In `@component/src/charts/bar-chart.tsx`:
- Around line 88-91: axisLabelRotation may be the sentinel -1 (meaning
"automatic") but is passed directly as rotateOverride to buildCategoryAxisLabel
causing an invalid angle; normalize axisLabelRotation to undefined when it
equals -1 before calling buildCategoryAxisLabel (e.g., compute a local
rotateOverride = axisLabelRotation === -1 ? undefined : axisLabelRotation and
pass that) so buildCategoryAxisLabel and axisLabelConfig receive undefined for
automatic mode rather than -1.

---

Nitpick comments:
In `@component/src/charts/chart-utils.ts`:
- Around line 40-49: Update the rotation selection logic to treat negative
rotateOverride values (e.g., -1 sentinel) as "automatic" rather than a literal
override: when determining rotate (using the rotateOverride and categoryCount
variables), only accept rotateOverride if it is defined and within the valid
0–90 range; if rotateOverride is undefined or negative (or out of range) fall
back to the categoryCount heuristics (categoryCount >= 15 => 45, >= 8 => 30,
else 0). Ensure this defensive check is applied where rotate and rotateOverride
are used so future callers cannot force invalid rotations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 08131565-6b82-4340-8b41-ac236444252f

📥 Commits

Reviewing files that changed from the base of the PR and between 59e78c2 and b826fac.

📒 Files selected for processing (4)
  • component/src/charts/__tests__/axis-label-utils.test.ts
  • component/src/charts/bar-chart.tsx
  • component/src/charts/chart-utils.ts
  • component/src/components/composed/chart-options-schema.ts

Comment thread component/src/charts/__tests__/axis-label-utils.test.ts
Comment on lines +88 to +91
const axisLabelConfig = buildCategoryAxisLabel(categoryLabels.length, {
compact,
rotateOverride: axisLabelRotation,
});

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 | 🔴 Critical

Sentinel value -1 not normalized before passing to utility.

When axisLabelRotation is -1 (the schema default for "automatic"), it's passed directly to buildCategoryAxisLabel as rotateOverride. The utility treats any defined value as an explicit override, resulting in rotate: -1 — an invalid ECharts angle.

Normalize -1 to undefined before passing:

🐛 Proposed fix
     const axisLabelConfig = buildCategoryAxisLabel(categoryLabels.length, {
       compact,
-      rotateOverride: axisLabelRotation,
+      rotateOverride: axisLabelRotation === -1 ? undefined : axisLabelRotation,
     });
📝 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 axisLabelConfig = buildCategoryAxisLabel(categoryLabels.length, {
compact,
rotateOverride: axisLabelRotation,
});
const axisLabelConfig = buildCategoryAxisLabel(categoryLabels.length, {
compact,
rotateOverride: axisLabelRotation === -1 ? undefined : axisLabelRotation,
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@component/src/charts/bar-chart.tsx` around lines 88 - 91, axisLabelRotation
may be the sentinel -1 (meaning "automatic") but is passed directly as
rotateOverride to buildCategoryAxisLabel causing an invalid angle; normalize
axisLabelRotation to undefined when it equals -1 before calling
buildCategoryAxisLabel (e.g., compute a local rotateOverride = axisLabelRotation
=== -1 ? undefined : axisLabelRotation and pass that) so buildCategoryAxisLabel
and axisLabelConfig receive undefined for automatic mode rather than -1.

alfredorubin96 and others added 2 commits March 23, 2026 01:40
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The -1 sentinel (automatic mode) was passed directly to ECharts as
rotate: -1 which is invalid. Now normalized to undefined so ECharts
uses its default auto-rotation. Added test for -1 sentinel case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

alfredo1996 pushed a commit that referenced this pull request Mar 24, 2026
…els, markLine, pie donut)

Merges PRs #169, #170, #171, #173, #174 into a single release branch.
Resolves merge conflicts in chart-utils.ts, bar-chart.tsx, line-chart.tsx,
and chart-options-schema.ts.

Includes:
- Number formatting for single-value and tooltips (#169)
- DataZoom support for bar and line charts (#170)
- Auto-rotate and truncate axis labels (#171)
- Reference lines (markLine) for bar and line charts (#173)
- Donut center text and Top-N grouping for pie chart (#174)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@alfredo1996

Copy link
Copy Markdown
Owner Author

Superseded by consolidated PR #185 (release/chart-improvements)

@alfredo1996
alfredo1996 deleted the feat/issue-137-axis-labels branch March 29, 2026 22:22
alfredo1996 pushed a commit that referenced this pull request May 10, 2026
…els, markLine, pie donut)

Merges PRs #169, #170, #171, #173, #174 into a single release branch.
Resolves merge conflicts in chart-utils.ts, bar-chart.tsx, line-chart.tsx,
and chart-options-schema.ts.

Includes:
- Number formatting for single-value and tooltips (#169)
- DataZoom support for bar and line charts (#170)
- Auto-rotate and truncate axis labels (#171)
- Reference lines (markLine) for bar and line charts (#173)
- Donut center text and Top-N grouping for pie chart (#174)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:charts Chart rendering enhancement New feature or request pkg:component UI component library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(component): auto-rotate and truncate axis labels

2 participants