Skip to content

fix(xlsx): clip anchored charts/images/drawings to the grid's freeze panes - #6

Merged
eric8810 merged 1 commit into
arcships:masterfrom
Taozizz:fix/xlsx-anchored-pane-clipping
Jul 30, 2026
Merged

fix(xlsx): clip anchored charts/images/drawings to the grid's freeze panes#6
eric8810 merged 1 commit into
arcships:masterfrom
Taozizz:fix/xlsx-anchored-pane-clipping

Conversation

@Taozizz

@Taozizz Taozizz commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Problem

The XLSX chart, image, and drawing overlays spanned the whole sheet surface with no clipping. Anchored objects are positioned as anchor position − scroll offset, so once the grid scrolled past an object's origin the offset went negative and the object painted over the column/row headers, the formula bar, and the host UI around the viewer:

  • Charts/images floated on top of the toolbar and formula bar after scrolling down
  • Objects also slid over the frozen panes region, which real Excel never allows

Fix

Clip anchored objects per freeze pane, the way Excel does.

  • New components/grid-metrics.ts is the single source for anchored-object geometry:
    • gridBodyLayerStyle insets the overlay layers past the row/column headers
    • createGridPaneLayout() splits the grid body into up to four overflow: hidden sub-panes (main / frozen-rows / frozen-cols / frozen-corner), assigns each object to the pane owning its anchor origin, and compensates scroll only on the scrolling axes
    • Frozen panes stack above the main pane, matching the canvas paint order
  • XlsxChartOverlay / XlsxImageLayer / XlsxDrawingLayer become thin views over that module — their three hand-copied versions of the frozen-extent / anchor-rect / scroll-compensation math are deleted
  • XlsxGrid now derives its header constants from the same module instead of local literals

Also fixed

GRID_ROW_HEADER_WIDTH in composables/internal.ts said 40 while XlsxGrid actually paints a 48px gutter. The constant only feeds the public rect APIs (getChartRect / setChartRect / getImageRect / setImageRect), which were self-consistent but horizontally offset by 8px from on-screen geometry. Aligned to 48 with internal.ts as the single source. Note: the exported constant's value changes, so hosts that manually compensated for the 8px skew would need to drop that compensation.

Testing

  • New tests/component/xlsx-anchored-panes.test.mjs: exact-coordinate assertions that freeze panes split into independently clipped panes, the frozen strip only follows horizontal scroll, and the main pane compensates both axes
  • Component suite 81/83 (the 2 failures are pre-existing on master in xlsx-menu-state.test.mjs, unrelated source-regex assertions), XLSX unit tests 29/29, workspace typecheck and vue-xlsx build clean
  • Manually verified in the demo (financial-model.xlsx P&L sheet and charts-images.xlsx): charts, images, shapes, and form controls scroll with the cells and clip exactly at the grid-body edge

Before

Screenshot 2026-07-27 at 8 32 48 PM

After

Screenshot 2026-07-27 at 10 57 45 PM

🤖 Generated with Claude Code

…panes

The chart, image, and drawing layers spanned the whole sheet surface
with no clipping, so anchored objects scrolled past the grid origin
painted over the column/row headers, the formula bar, and the host UI
around the viewer. Each layer also carried its own copy of the
frozen-extent, anchor-rect, and scroll-compensation math.

Consolidate the geometry in grid-metrics.ts: createGridPaneLayout()
derives the freeze-pane sub-boxes (main / frozen-rows / frozen-cols /
frozen-corner) inside a grid-body layer inset past the headers, and
places each object in the pane owning its anchor origin, compensating
scroll only on the scrolling axes. The three layers become thin views
that group items by pane; each pane clips its own objects the way Excel
clips drawings per pane, with frozen panes stacked above the main pane
to match the canvas paint order.

Also align the public GRID_ROW_HEADER_WIDTH constant (40 -> 48) with
the gutter XlsxGrid actually paints, so setChartRect/getChartRect
coordinates agree with on-screen geometry; internal.ts is now the
single source for both header metrics.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eric8810
eric8810 merged commit 391f0a6 into arcships:master Jul 30, 2026
1 check passed
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.

2 participants