Skip to content

Commit aafb83d

Browse files
committed
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
1 parent 1bc4216 commit aafb83d

6 files changed

Lines changed: 173 additions & 3 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"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.",
5+
"type": "none",
6+
"packageName": "@visactor/vchart"
7+
}
8+
],
9+
"packageName": "@visactor/vchart",
10+
"email": "lixuef1313@163.com"
11+
}

packages/vchart/__tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,48 @@ describe('ScrollBar', () => {
7676
expect(attrs.range[0]).toBeCloseTo(0.98);
7777
expect(attrs.range[1]).toBeCloseTo(1);
7878
});
79+
80+
it('should map reversed vertical axis state to top-first domain values', () => {
81+
const spec: any = {
82+
orient: 'right'
83+
};
84+
85+
scrollBar = new ScrollBar(spec, option);
86+
87+
const handleStateChange = jest.fn().mockReturnValue(true);
88+
const emit = jest.fn();
89+
90+
(scrollBar as any)._handleStateChange = handleStateChange;
91+
(scrollBar as any)._stateScale = {
92+
type: 'band',
93+
range: () => [100, 0],
94+
domain: () => ['A', 'B', 'C', 'D'],
95+
invert: (value: number) => {
96+
if (value < 25) {
97+
return 'A';
98+
}
99+
if (value < 50) {
100+
return 'B';
101+
}
102+
if (value < 75) {
103+
return 'C';
104+
}
105+
return 'D';
106+
}
107+
};
108+
(scrollBar as any)._relatedAxisComponent = {
109+
getScale: () => ({
110+
range: () => [100, 0]
111+
}),
112+
getInverse: () => false
113+
};
114+
(scrollBar as any).event = { emit };
115+
(scrollBar as any)._start = 0;
116+
(scrollBar as any)._end = 1;
117+
118+
(scrollBar as any)._handleChange(0, 0.5);
119+
120+
expect(handleStateChange).toHaveBeenCalledWith('A', 'C');
121+
expect(emit).toHaveBeenCalled();
122+
});
79123
});

packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { Factory } from '../../../core/factory';
1616
import type { ILayoutType } from '../../../typings/layout';
1717
import { isClose } from '../../../util';
1818
import { scrollBar } from '../../../theme/builtin/common/component/scroll-bar';
19-
import { statePointToData } from '../util';
19+
import { isReverse, statePointToData } from '../util';
20+
import type { CartesianAxis } from '../../axis/cartesian';
2021
// import { SCROLLBAR_EVENT, SCROLLBAR_END_EVENT } from '@visactor/vrender-components/es/constant';
2122

2223
// 由vrender透出, 接入新版本后需修改
@@ -59,8 +60,10 @@ export class ScrollBar<T extends IScrollBarSpec = IScrollBarSpec> extends DataFi
5960

6061
this._start = start;
6162
this._end = end;
62-
const startValue = statePointToData(start, this._stateScale, false);
63-
const endValue = statePointToData(end, this._stateScale, false);
63+
const axis = this._relatedAxisComponent as CartesianAxis<any>;
64+
const reverse = isReverse(axis, this._isHorizontal);
65+
const startValue = statePointToData(start, this._stateScale, reverse);
66+
const endValue = statePointToData(end, this._stateScale, reverse);
6467
const hasChange = isFunction(this._spec.updateDataAfterChange)
6568
? this._spec.updateDataAfterChange(start, end, startValue, endValue)
6669
: this._handleStateChange(startValue, endValue);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Implementation Plan: Fix Heatmap Scrollbar Axis Direction
2+
3+
**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)
4+
**Input**: Feature specification from `/specs/009-fix-heatmap-scrollbar-axis-direction/spec.md`
5+
6+
## Summary
7+
8+
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.
9+
10+
## Technical Context
11+
12+
**Language/Version**: TypeScript 4.9.x
13+
**Primary Dependencies**: `@visactor/vscale`, `@visactor/vutils`, `@visactor/vrender-components`
14+
**Testing**: Jest 26 unit tests under `packages/vchart/__tests__`
15+
**Target Platform**: Browser and cross-platform cartesian chart runtime
16+
**Project Type**: Monorepo charting library package (`packages/vchart`)
17+
**Constraints**: Preserve existing `dataZoom` behavior; avoid changing axis range calculation; keep the fix scoped to scrollbar state-domain conversion
18+
19+
## Constitution Check
20+
21+
- Pass: The work is narrowly scoped to the documented bug.
22+
- Pass: The change reuses an existing shared utility instead of introducing a new behavior branch.
23+
- Pass: Regression coverage will be added for the user-visible bug path.
24+
25+
## Project Structure
26+
27+
```text
28+
specs/009-fix-heatmap-scrollbar-axis-direction/
29+
├── plan.md
30+
├── spec.md
31+
└── tasks.md
32+
```
33+
34+
```text
35+
packages/vchart/
36+
├── src/component/data-zoom/scroll-bar/scroll-bar.ts
37+
└── __tests__/unit/component/data-zoom/scroll-bar/scroll-bar.test.ts
38+
```
39+
40+
## Implementation Strategy
41+
42+
1. Update `ScrollBar._handleChange` to derive `startValue` and `endValue` with `isReverse(axis, this._isHorizontal)`.
43+
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.
44+
3. Run the focused Jest test file and inspect the diff for unintended churn.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Feature Specification: Fix Heatmap Scrollbar Axis Direction
2+
3+
**Feature Branch**: `009-fix-heatmap-scrollbar-axis-direction`
4+
**Created**: 2026-03-23
5+
**Status**: Draft
6+
**Input**: User description: "Fix VChart issue #4320: heatmap right scrollbar scroll direction is opposite to the left band axis order"
7+
8+
## User Scenarios & Testing *(mandatory)*
9+
10+
### User Story 1 - Keep Vertical Scroll Direction Consistent (Priority: P1)
11+
12+
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.
13+
14+
**Why this priority**: The reported bug breaks the primary interaction for scrolling long heatmap category axes and makes the chart feel inverted.
15+
16+
**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.
17+
18+
**Acceptance Scenarios**:
19+
20+
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.
21+
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.
22+
23+
### Edge Cases
24+
25+
- Vertical discrete axes whose internal scale range is reversed because of cartesian axis layout should still map scrollbar state to domain values correctly.
26+
- Horizontal scrollbars and already-correct dataZoom behavior must remain unchanged.
27+
28+
## Requirements *(mandatory)*
29+
30+
### Functional Requirements
31+
32+
- **FR-001**: The scrollbar component MUST resolve discrete axis domain values using the same reverse-axis logic as other data-filter components.
33+
- **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.
34+
- **FR-003**: Existing scrollbar behavior for non-reversed or horizontal axes MUST remain backward compatible.
35+
36+
## Success Criteria *(mandatory)*
37+
38+
### Measurable Outcomes
39+
40+
- **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.
41+
- **SC-002**: A focused automated regression test proves scrollbar state-to-domain conversion respects reversed vertical axis ranges.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Tasks: Heatmap Scrollbar Axis Direction
2+
3+
**Input**: Design documents from `/specs/009-fix-heatmap-scrollbar-axis-direction/`
4+
**Prerequisites**: plan.md, spec.md
5+
6+
**Tests**: Include focused unit regression coverage for the reversed vertical axis path.
7+
8+
## Phase 1: Setup
9+
10+
- [x] T001 Inspect scrollbar reverse-mapping logic and compare it with `dataZoom`
11+
12+
## Phase 2: User Story 1 - Keep Vertical Scroll Direction Consistent (Priority: P1)
13+
14+
**Goal**: Make right-side heatmap scrollbar movement and left-axis viewport order move in the same direction
15+
16+
### Tests for User Story 1
17+
18+
- [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`
19+
20+
### Implementation for User Story 1
21+
22+
- [x] T003 [US1] Reuse shared reverse-axis detection in `packages/vchart/src/component/data-zoom/scroll-bar/scroll-bar.ts`
23+
24+
## Phase 3: Polish
25+
26+
- [ ] T004 Run the focused Jest test for scrollbar regressions
27+
- [x] T005 Update task tracking after implementation

0 commit comments

Comments
 (0)