Skip to content

fix(plugin-charts): data labels print in their value axis's units and the tallest mark keeps its label on the chart - #27407

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-hbru8t
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-hbru8t

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #27372

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:图表数据标签改用其所在数值轴自己的刻度格式化器(无作者格式时与轴同为紧凑单位,如 174K),并在开启数据标签时给竖向图表加顶部留白,最高柱的标签不再画到图外。
  • 为什么改:HotCRM 18.2.0 浏览器走查第 2–3 行:标签印 174000 而轴印 400K;最高柱的值标签整段被裁掉。表格末列与全零图两行实测后不改,理由见下。
  • 风险与回滚:只动 @object-ui/plugin-charts 的 AdvancedChartImpl.tsx;关闭数据标签的图表与横向柱图布局字节不变。回滚 = revert 本 PR。
  • 先看:AdvancedChartImpl.tsx 的 DATA_LABEL_CHART_MARGIN 与 dataLabel / valueTickFormatterOf;再看新测试 AdvancedChartImpl.dataLabels-27372.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/plugin-charts/src/AdvancedChartImpl.dataLabels-27372.test.tsx,预期 11 passed。
  • 需要你做的:无,席位落地。

What changes

ui/packages/plugin-charts/src/AdvancedChartImpl.tsx only:

  • Row 2: data labels read in their axis's units. dataLabel now takes the tick formatter of the value axis the series is drawn against: yTickFormatter on a single-axis chart, leftYTickFormatter / rightYTickFormatter by the series' yAxis on a dual-axis chart (valueTickFormatterOf), and by the series' axis id on a combo. Each of those is already formatterFor(axis.format) ?? formatYTick, so an authored yAxis[].format still wins and an axis without one gives its labels the compact default. Before, the label called formatterFor(axis.format) with no fallback and printed the raw number. Dashboard charts are the common case: chartConfig carries no axis format at all.
  • Row 3, tallest bar: label headroom. With showDataLabels on, a vertical bar, line, area or combo chart takes DATA_LABEL_CHART_MARGIN: a top margin of recharts' 5px plus the label's offset (5px) and font (11px). A margin rather than a domain pad, so an authored yAxis.max keeps pinning the domain. Charts without data labels and horizontal bars keep recharts' default margin. The label's font size and offset are now named constants (DATA_LABEL_FONT_PX, DATA_LABEL_OFFSET_PX); their values are unchanged.
  • The unused axisOfSeries helper is replaced by valueTickFormatterOf.

Serial constraint with #27361: this diff does not touch DatasetWidget.tsx or utils.ts and does not regenerate the sdui manifest, so it does not wait on #27361.

Why

Rows 2–4 of #27355 (HotCRM's 18.2.0 browser pass), carded as #27372. Each row was measured in real Chromium (/opt/pw-browsers/chromium) on a fixture dashboard rendered by the real DashboardRenderer, with dataset-bound bar, line, table and all-zero widgets and an object-provider table, at 1280px (tables also at 768px and 390px). HotCRM's metadata was not used.

Row Reading before (c4c515ad) Reading after Outcome
2 Label 174000 beside y ticks 0 / 100K / … / 400K Label 174K, ticks unchanged done
3a Tallest label 400000 box top at −11px from the svg top: outside the svg 400K box top at +5px: inside the svg done
3b Dataset table: scroller overflow-x: auto, scrollWidth 910 vs clientWidth 566, inside the card. Object-provider table: 971 vs 564, inside the card (no change) will not do: not reproduced
4 All-zero bar and line: y ticks 0 1 2 3 4, 5 grid/axis lines, the line drawn on 0 (no change) will not do

Acceptance notes

  • Row 3b, not reproduced. Neither dashboard table widget clips its last column out of reach. The dataset table (DatasetWidget's flat table) and the provider: 'object' table (ObjectDataTable → data-table) each keep their own overflow-auto scroller inside the card, and the last column scrolls into view at 1280, 768 and 390px. What reads as a clip is the scroll edge with no visible scrollbar: headless Chromium hides scrollbars by default, macOS shows them only while scrolling, and data-table shows its scrollbar on hover only. A visible overflow cue (an edge fade, say) would be polish, not a reachability defect, so no table widget is changed. If HotCRM's screen shows a column that cannot be scrolled to, the reading needed is the widget type and the scroller's scrollWidth / clientWidth there.
  • Row 4, will not do. The recorded decision in AdvancedChartImpl.tsx (the "all-zero BAR drew 5,128 ink pixels of axes and ticks" paragraph) stands: zero is a value, the measured chart draws a usable zero baseline and ticks, and a "no data" state over real zeros would be false.
  • Field format does not reach labels or ticks. A measure's field currency / percent format reaches neither the axis ticks nor the labels on a dashboard chart (both read only yAxis[].format, which chartConfig does not carry). Not widened here: the labels now match the axis, which is the card's ask.
  • A horizontal bar's labels sit in the band beside each bar and were not measured as clipped; they get no new margin.

Verification

Head 27cff9de.

New pin: AdvancedChartImpl.dataLabels-27372.test.tsx (11 cases)
  • Compact default beside a compact axis, for bar, line and area (['174K', '400K', '251K', '92.5K'], the axis itself asserted to read 400K).
  • An authored $0,0 format wins ($174,000 …).
  • Dual-axis bar and combo: each series prints in its own axis's units (174K … left, 12.0 … right with a right-axis 0.0 format).
  • The tallest label's baseline minus the label font is ≥ 0 for bar, line, area and combo; the plot top stays at 5px with labels off.

pnpm --dir ui exec vitest run packages/plugin-charts/src/AdvancedChartImpl.dataLabels-27372.test.tsx → 11 passed.

Ablations (each fix reverted through scripts/ablation-replace.mjs, restored blob = HEAD)
  • Formatter dropped from the LabelList (raw labels): 10 of 11 red (expected [ '174000', … ] to deeply equal [ '174K', … ]); only the labels-off margin case stays green.
  • Top margin set back to 5px: exactly the 4 headroom cases red ("400K" is drawn above the chart surface: expected -11 to be greater than or equal to 0), the 7 others green.
Package and gates
  • pnpm --filter @object-ui/plugin-charts type-check and pnpm --dir ui exec vitest run packages/plugin-charts/ → exit 0; Test Files 100 passed (100), Tests 1292 passed | 9 skipped (1301), on 27cff9d.
  • eslint on both touched files: 0 errors; warning count equal to c4c515ad (41).
  • pnpm --dir ui run check:new-line-citations → 0 new citations.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 35 derived, 35 run on 27cff9d; 34 exit 0 first pass. pnpm --dir ui exec vitest run scripts/ exit 1 on one 15 s timeout in check-vi-mock-inherit.test.ts (tree-sweep population test, a load timeout on a shared box; this diff touches no ui/scripts input); that file re-run alone under the lock: 83/83 passed, exit 0. --ran reconciliation: 35 accounted, 0 NOT-MEASURED, 0 UNRUN.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes (touched files linted; repo-wide lint is CI's).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset (@object-ui/plugin-charts patch).
  • 6. packages/spec touched: n/a.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block is the dispatch order's required Chinese summary).
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbY75sPQWcfUg8cZQhg


Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Oct 29, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#5 · os-warren · session_01JQwxbXGpVJHZTXXerMoY4C

席位核对

ACCEPT · seat domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · head 27cff9de · 2026-10-29T05:36Z

席位意见:图表的数据标签现在用所在数值轴自己的刻度格式化器,没有作者格式时和轴一样显示紧凑单位(174K 和 400K 并排,不再出现 174000)。开启数据标签的竖向图表顶部留出一行标签的高度,最高柱的数值不再被裁掉。第 3b 行(表格末列)实测能在卡片内滚动,没能复现;第 4 行(全零图)保留原有的测量结论。这两行都不改,理由写在 PR 里。

  1. Shape: Fixes #27372. 3 files, +220/−11:
    • AdvancedChartImpl.tsx:
      • valueTickFormatterOf replaces axisOfSeries.
      • dataLabel now requires the formatter.
      • DATA_LABEL_CHART_MARGIN applies only when showDataLabels is on and the chart is not a horizontal bar.
    • A new test file with 11 pins.
    • A patch changeset for @object-ui/plugin-charts.
  2. Premise measured: the seat's reading held for row 2 and row 3a. The dev measured both in Chromium on a fixture rendered by the real DashboardRenderer:
    • The label went from 174000 to 174K.
    • The tallest label's box moved from −11px to +5px inside the svg.
    • The seat read the diff. Each formatter is the axis's own formatterFor(format) ?? formatYTick, so an authored format still wins, per axis on dual and combo charts. The margin keeps the left and right 5px that CHART_MARGIN_X_PX counts on, and an authored yAxis.max still pins the domain.
  3. Gates / check-runs:
    • PR check-runs on 27cff9de: 44 success, 11 skipped (path-filtered), 0 failure; mergeable_state clean.
    • Dev: ran 35 of 35 derived gates. One ui scripts/ file timed out at 15s on the shared box and passed 83/83 when re-run alone.
    • Both ablations turned red and were restored.
  4. Accepted deviations: none. "Will not do" for rows 3b and 4 is an outcome the order allowed, and each is measured:
    • 3b: scrollWidth 910/566 and 971/564, and the column scrolls into view at 1280, 768 and 390px. What looks like a clip is a hidden or overlay scrollbar.
    • 4: ticks 0–4, the grid and the zero line stay, and the recorded decision stands.
  5. Out of scope:
  6. Landing: not Tier H, since no governed path is touched. Clause-②: no. Ready for landing (ready + auto-merge).

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 29, 2026 05:37
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit 45c9be5 Oct 29, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-hbru8t branch October 29, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

2 participants