From ac7b651f8575b1d9a42c37be2fd09087e2d56e62 Mon Sep 17 00:00:00 2001 From: xuefei1313 Date: Mon, 23 Mar 2026 09:09:42 +0000 Subject: [PATCH] fix(vchart): Fix the heatmap scrollbar and left-axis direction mismatch by aligning ScrollBar with DataZoom when converting scrollbar state percentages back into domain values --- ...llbar-axis-direction_2026-03-23-09-08.json | 11 +++++ .../data-zoom/scroll-bar/scroll-bar.test.ts | 44 +++++++++++++++++++ .../data-zoom/scroll-bar/scroll-bar.ts | 9 ++-- .../plan.md | 44 +++++++++++++++++++ .../spec.md | 41 +++++++++++++++++ .../tasks.md | 27 ++++++++++++ 6 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 common/changes/@visactor/vchart/009-fix-heatmap-scrollbar-axis-direction_2026-03-23-09-08.json create mode 100644 specs/009-fix-heatmap-scrollbar-axis-direction/plan.md create mode 100644 specs/009-fix-heatmap-scrollbar-axis-direction/spec.md create mode 100644 specs/009-fix-heatmap-scrollbar-axis-direction/tasks.md diff --git a/common/changes/@visactor/vchart/009-fix-heatmap-scrollbar-axis-direction_2026-03-23-09-08.json b/common/changes/@visactor/vchart/009-fix-heatmap-scrollbar-axis-direction_2026-03-23-09-08.json new file mode 100644 index 0000000000..a8adc3479c --- /dev/null +++ b/common/changes/@visactor/vchart/009-fix-heatmap-scrollbar-axis-direction_2026-03-23-09-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "update changes for 009-fix-heatmap-scrollbar-axis-direction: Align ScrollBar with DataZoom by using the shared reverse-axis detection when converting scrollbar state percentages back into domain values.", + "type": "none", + "packageName": "@visactor/vchart" + } + ], + "packageName": "@visactor/vchart", + "email": "lixuef1313@163.com" +} \ No newline at end of file diff --git a/packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts b/packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts index 6a7653b31d..448e6108a8 100644 --- a/packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts +++ b/packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts @@ -76,4 +76,48 @@ describe('ScrollBar', () => { expect(attrs.range[0]).toBeCloseTo(0.98); expect(attrs.range[1]).toBeCloseTo(1); }); + + it('should map reversed vertical axis state to top-first domain values', () => { + const spec: any = { + orient: 'right' + }; + + scrollBar = new ScrollBar(spec, option); + + const handleStateChange = jest.fn().mockReturnValue(true); + const emit = jest.fn(); + + (scrollBar as any)._handleStateChange = handleStateChange; + (scrollBar as any)._stateScale = { + type: 'band', + range: () => [100, 0], + domain: () => ['A', 'B', 'C', 'D'], + invert: (value: number) => { + if (value < 25) { + return 'A'; + } + if (value < 50) { + return 'B'; + } + if (value < 75) { + return 'C'; + } + return 'D'; + } + }; + (scrollBar as any)._relatedAxisComponent = { + getScale: () => ({ + range: () => [100, 0] + }), + getInverse: () => false + }; + (scrollBar as any).event = { emit }; + (scrollBar as any)._start = 0; + (scrollBar as any)._end = 1; + + (scrollBar as any)._handleChange(0, 0.5); + + expect(handleStateChange).toHaveBeenCalledWith('A', 'C'); + expect(emit).toHaveBeenCalled(); + }); }); diff --git a/packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts b/packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts index 21958104bc..7df191b913 100644 --- a/packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts +++ b/packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts @@ -16,7 +16,8 @@ import { Factory } from '../../../core/factory'; import type { ILayoutType } from '../../../typings/layout'; import { isClose } from '../../../util'; import { scrollBar } from '../../../theme/builtin/common/component/scroll-bar'; -import { statePointToData } from '../util'; +import { isReverse, statePointToData } from '../util'; +import type { CartesianAxis } from '../../axis/cartesian'; // import { SCROLLBAR_EVENT, SCROLLBAR_END_EVENT } from '@visactor/vrender-components/es/constant'; // 由vrender透出, 接入新版本后需修改 @@ -59,8 +60,10 @@ export class ScrollBar extends DataFi this._start = start; this._end = end; - const startValue = statePointToData(start, this._stateScale, false); - const endValue = statePointToData(end, this._stateScale, false); + const axis = this._relatedAxisComponent as CartesianAxis; + const reverse = isReverse(axis, this._isHorizontal); + const startValue = statePointToData(start, this._stateScale, reverse); + const endValue = statePointToData(end, this._stateScale, reverse); const hasChange = isFunction(this._spec.updateDataAfterChange) ? this._spec.updateDataAfterChange(start, end, startValue, endValue) : this._handleStateChange(startValue, endValue); diff --git a/specs/009-fix-heatmap-scrollbar-axis-direction/plan.md b/specs/009-fix-heatmap-scrollbar-axis-direction/plan.md new file mode 100644 index 0000000000..44a3a2dbf6 --- /dev/null +++ b/specs/009-fix-heatmap-scrollbar-axis-direction/plan.md @@ -0,0 +1,44 @@ +# Implementation Plan: Fix Heatmap Scrollbar Axis Direction + +**Branch**: `009-fix-heatmap-scrollbar-axis-direction` | **Date**: 2026-03-23 | **Spec**: [/data00/home/lixuefei.1313/github/VChart/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md](/data00/home/lixuefei.1313/github/VChart/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md) +**Input**: Feature specification from `/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md` + +## Summary + +Fix the heatmap scrollbar and left-axis direction mismatch by aligning `ScrollBar` with `DataZoom` when converting scrollbar state percentages back into domain values. Add a focused regression test covering a vertical reversed discrete axis, which is the path exercised by the heatmap reproduction. + +## Technical Context + +**Language/Version**: TypeScript 4.9.x +**Primary Dependencies**: `@visactor/vscale`, `@visactor/vutils`, `@visactor/vrender-components` +**Testing**: Jest 26 unit tests under `packages/vchart/__tests__` +**Target Platform**: Browser and cross-platform cartesian chart runtime +**Project Type**: Monorepo charting library package (`packages/vchart`) +**Constraints**: Preserve existing `dataZoom` behavior; avoid changing axis range calculation; keep the fix scoped to scrollbar state-domain conversion + +## Constitution Check + +- Pass: The work is narrowly scoped to the documented bug. +- Pass: The change reuses an existing shared utility instead of introducing a new behavior branch. +- Pass: Regression coverage will be added for the user-visible bug path. + +## Project Structure + +```text +specs/009-fix-heatmap-scrollbar-axis-direction/ +├── plan.md +├── spec.md +└── tasks.md +``` + +```text +packages/vchart/ +├── src/component/data-zoom/scroll-bar/scroll-bar.ts +└── __tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts +``` + +## Implementation Strategy + +1. Update `ScrollBar._handleChange` to derive `startValue` and `endValue` with `isReverse(axis, this._isHorizontal)`. +2. Add a regression test that mocks a reversed vertical band axis and asserts scrollbar state `0 -> 0.5` maps to the top half of the domain. +3. Run the focused Jest test file and inspect the diff for unintended churn. diff --git a/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md b/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md new file mode 100644 index 0000000000..f9cc36423c --- /dev/null +++ b/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md @@ -0,0 +1,41 @@ +# Feature Specification: Fix Heatmap Scrollbar Axis Direction + +**Feature Branch**: `009-fix-heatmap-scrollbar-axis-direction` +**Created**: 2026-03-23 +**Status**: Draft +**Input**: User description: "Fix VChart issue #4320: heatmap right scrollbar scroll direction is opposite to the left band axis order" + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Keep Vertical Scroll Direction Consistent (Priority: P1) + +As a chart author using a heatmap with a right-side vertical scrollbar, I want the visible left-axis labels to move in the same direction as the scrollbar thumb so that the viewport behaves consistently with bar charts and user expectations. + +**Why this priority**: The reported bug breaks the primary interaction for scrolling long heatmap category axes and makes the chart feel inverted. + +**Independent Test**: Render a heatmap with a left `band` axis and a right `scrollBar` bound to the same Y field. Move the scrollbar to the top and verify the axis viewport shows the first categories rather than the last categories. + +**Acceptance Scenarios**: + +1. **Given** a heatmap whose Y axis is a vertical band axis and whose `scrollBar.orient` is `right`, **When** the scrollbar range starts at `0`, **Then** the left axis viewport shows the earliest/top categories in the axis domain. +2. **Given** the same chart, **When** the scrollbar is dragged downward, **Then** the visible Y-axis categories advance downward in the same direction as the scrollbar thumb. + +### Edge Cases + +- Vertical discrete axes whose internal scale range is reversed because of cartesian axis layout should still map scrollbar state to domain values correctly. +- Horizontal scrollbars and already-correct dataZoom behavior must remain unchanged. + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: The scrollbar component MUST resolve discrete axis domain values using the same reverse-axis logic as other data-filter components. +- **FR-002**: For vertical cartesian band axes, a scrollbar state near `start = 0` MUST map to the top of the visible axis domain instead of the bottom when the axis scale range is reversed by layout. +- **FR-003**: Existing scrollbar behavior for non-reversed or horizontal axes MUST remain backward compatible. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: In the issue #4320 reproduction, placing the right scrollbar thumb at the top shows the top portion of the heatmap Y-axis domain. +- **SC-002**: A focused automated regression test proves scrollbar state-to-domain conversion respects reversed vertical axis ranges. diff --git a/specs/009-fix-heatmap-scrollbar-axis-direction/tasks.md b/specs/009-fix-heatmap-scrollbar-axis-direction/tasks.md new file mode 100644 index 0000000000..7e9c6ea518 --- /dev/null +++ b/specs/009-fix-heatmap-scrollbar-axis-direction/tasks.md @@ -0,0 +1,27 @@ +# Tasks: Heatmap Scrollbar Axis Direction + +**Input**: Design documents from `/specs/009-fix-heatmap-scrollbar-axis-direction/` +**Prerequisites**: plan.md, spec.md + +**Tests**: Include focused unit regression coverage for the reversed vertical axis path. + +## Phase 1: Setup + +- [x] T001 Inspect scrollbar reverse-mapping logic and compare it with `dataZoom` + +## Phase 2: User Story 1 - Keep Vertical Scroll Direction Consistent (Priority: P1) + +**Goal**: Make right-side heatmap scrollbar movement and left-axis viewport order move in the same direction + +### Tests for User Story 1 + +- [x] T002 [US1] Add a scrollbar regression test for reversed vertical axis mapping in `packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts` + +### Implementation for User Story 1 + +- [x] T003 [US1] Reuse shared reverse-axis detection in `packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts` + +## Phase 3: Polish + +- [ ] T004 Run the focused Jest test for scrollbar regressions +- [x] T005 Update task tracking after implementation