diff --git a/.cursor/rules/specify-rules.mdc b/.cursor/rules/specify-rules.mdc index 0687c8a289..29a80f02e5 100644 --- a/.cursor/rules/specify-rules.mdc +++ b/.cursor/rules/specify-rules.mdc @@ -3,6 +3,8 @@ Auto-generated from all feature plans. Last updated: 2026-01-15 ## Active Technologies +- TypeScript 4.x+ (Project uses TS) + `@visactor/vchart` (Core logic), `@visactor/react-vchart` (React wrapper) (007-fix-datazoom-react) +- N/A (In-memory chart state) (007-fix-datazoom-react) - TypeScript/React 18 + @visactor/react-vchart, @visactor/vchar (001-react-vchart-demo) @@ -24,11 +26,11 @@ npm test && npm run lint TypeScript 4.9.5: Follow standard conventions ## Recent Changes +- 007-fix-datazoom-react: Added TypeScript 4.x+ (Project uses TS) + `@visactor/vchart` (Core logic), `@visactor/react-vchart` (React wrapper) +- 007-fix-datazoom-react: Added [if applicable, e.g., PostgreSQL, CoreData, files or N/A] - 001-react-vchart-demo: Added TypeScript/React 18 + @visactor/react-vchart, @visactor/vchar -- 001-react-vchart-demo: Added [if applicable, e.g., PostgreSQL, CoreData, files or N/A] -- 001-scrollbar-wheel-step: Added TypeScript 4.9.5 + @visactor/vchart, @visactor/vrender-components (~1.0.37), @visactor/vutils diff --git a/.trae/documents/plan_20260214_031224.md b/.trae/documents/plan_20260214_031224.md new file mode 100644 index 0000000000..f7728f4736 --- /dev/null +++ b/.trae/documents/plan_20260214_031224.md @@ -0,0 +1,27 @@ +# Implementation Plan: Fix DataZoom Value Update on Data Change in React + +**Branch**: `007-fix-datazoom-react` +**Spec**: [specs/007-fix-datazoom-react/spec.md](../spec.md) + +## Summary +I have planned the fix for Issue #4185 where DataZoom fails to update in React when data changes. The plan involves detecting data view changes in the core `DataFilterBaseComponent` and rebinding listeners, ensuring the component stays in sync with the latest data. + +## Phase 1: Setup (Reproduction) +- [ ] Initialize reproduction in `packages/react-vchart/demo/src/BugReproduction.tsx` +- [ ] Update demo entry point to run reproduction + +## Phase 3: User Story 1 (Core Fix) +- [ ] Implement `_collectDataInfo` helper to gather data view references +- [ ] Add state tracking for `_currentDataCollection` and bound listeners +- [ ] Update `_initData` to initialize tracking +- [ ] Implement robust `onDataUpdate` logic: + - Detect if underlying DataViews have changed + - Unbind old listeners / Bind new listeners + - Re-run data transforms to update domain + - **Crucial**: Apply explicit `start`/`end` from spec if present (resetting range as per user config) + +## Phase N: Polish +- [ ] Clean up reproduction code +- [ ] Restore demo entry point + +I am ready to proceed with the implementation. Please confirm. \ No newline at end of file diff --git a/common/changes/@visactor/react-vchart/fix-datazoom-update_20250209.json b/common/changes/@visactor/react-vchart/fix-datazoom-update_20250209.json new file mode 100644 index 0000000000..ba8a1705a5 --- /dev/null +++ b/common/changes/@visactor/react-vchart/fix-datazoom-update_20250209.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@visactor/react-vchart", + "comment": "fix: ensure DataZoom updates when data source changes (Issue #4185)", + "type": "patch" + } + ], + "packageName": "@visactor/react-vchart", + "email": "test@example.com" +} diff --git a/common/changes/@visactor/vchart/fix-datazoom-update_20250209.json b/common/changes/@visactor/vchart/fix-datazoom-update_20250209.json new file mode 100644 index 0000000000..773627e18c --- /dev/null +++ b/common/changes/@visactor/vchart/fix-datazoom-update_20250209.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "fix: ensure DataZoom updates when data source changes (Issue #4185)", + "type": "patch" + } + ], + "packageName": "@visactor/vchart", + "email": "test@example.com" +} diff --git a/packages/vchart/src/component/data-zoom/data-filter-base-component.ts b/packages/vchart/src/component/data-zoom/data-filter-base-component.ts index 92ead75276..3c5748098f 100644 --- a/packages/vchart/src/component/data-zoom/data-filter-base-component.ts +++ b/packages/vchart/src/component/data-zoom/data-filter-base-component.ts @@ -134,6 +134,9 @@ export abstract class DataFilterBaseComponent { @@ -551,14 +555,14 @@ export abstract class DataFilterBaseComponent dv !== dataCollection[i]) + ) { + this._currentDataCollection.forEach(dv => { + dv?.target?.removeListener('change', this._handleDataCollectionChangeBound); + }); + this._currentDataCollection = dataCollection; + const { dataSet } = this._option; + dataSet.multipleDataViewAddListener(this._currentDataCollection, 'change', this._handleDataCollectionChangeBound); + } + + // 2. 执行数据更新 + this._data.getDataView().transform( + { + type: 'dataFilterComputeDomain', + options: { + input: { + dataCollection: dataCollection, + seriesCollection, + stateFields, + valueFields, + isCategoryState + }, + output: { + stateField: this._stateField, + valueField: this._valueField + } + } + }, + false + ); + this._data.getDataView().reRunAllTransform(); + + // 3. 重新计算domain const domain = this._computeDomainOfStateScale(isContinuous(this._stateScale.type)); this._stateScale.domain(domain, false); + + // 4. 重新计算start和end + // 如果 spec 中有配置 start/end,使用 spec 中的配置 + // 否则保持当前的 start/end + if (isValid(this._spec.start) || isValid(this._spec.end)) { + this._setStateFromSpec(); + } this._handleChange(this._start, this._end, true); + + // 5. 重新布局 // auto 模式下需要重新布局 if (this._spec.auto && !isEqual(this._domainCache, domain)) { this._domainCache = domain; @@ -747,13 +806,13 @@ export abstract class DataFilterBaseComponent Plan -> Tasks). +- [x] **Openness & Collaboration**: Code will be reviewed via PR. +- [x] **Monorepo/Rush Governance**: Changes will be in `packages/vchart` (core logic) and `packages/react-vchart` (if needed for prop handling, though core fix likely sufficient). +- [x] **TypeScript**: Strict typing required. +- [x] **Testing**: Unit tests required for new logic. + +## Project Structure + +### Documentation (this feature) + +```text +specs/007-fix-datazoom-react/ +├── plan.md # This file +├── research.md # Phase 0 output +├── data-model.md # Phase 1 output (N/A for this fix) +├── quickstart.md # Phase 1 output (N/A) +├── contracts/ # Phase 1 output (N/A) +└── tasks.md # Phase 2 output +``` + +### Source Code (repository root) + +```text +packages/ +├── vchart/ +│ └── src/ +│ └── component/ +│ └── data-zoom/ +│ └── data-filter-base-component.ts # Core logic modification target +└── react-vchart/ + └── demo/ + └── src/ + └── BugReproduction.tsx # Verification demo +``` + +**Structure Decision**: Modification is primarily in `@visactor/vchart` core component logic to robustly handle data view changes. + +## Complexity Tracking + +| Violation | Why Needed | Simpler Alternative Rejected Because | +|-----------|------------|-------------------------------------| +| None | | | diff --git a/specs/007-fix-datazoom-react/spec.md b/specs/007-fix-datazoom-react/spec.md new file mode 100644 index 0000000000..8e1d810bf1 --- /dev/null +++ b/specs/007-fix-datazoom-react/spec.md @@ -0,0 +1,68 @@ +# Feature Specification: Fix DataZoom Value Update on Data Change in React + +**Feature Branch**: `007-fix-datazoom-react` +**Created**: 2025-02-09 +**Status**: Draft +**Input**: User description: "Fix DataZoom value not updating after data update in React (Issue #4185)" + +## Clarifications + +### Session 2025-02-09 + +- Q: How should DataZoom range behave when data updates? → A: Reset range based on user configuration (props/spec). If user explicitly sets `start: 0, end: 0.2`, respect that on update. + +## User Scenarios & Testing _(mandatory)_ + +### User Story 1 - DataZoom Synchronization on Data Update (Priority: P1) + +As a developer using ReactVChart, I want the DataZoom component to automatically update its state (value range and preview) when I update the chart's data source, so that the data navigation control accurately reflects the new dataset. + +**Why this priority**: This is a critical bug fix. Currently, when data changes in a React environment, the DataZoom component may retain stale references to old data or fail to update its internal state, leading to broken interaction and incorrect visual feedback. + +**Independent Test**: + +1. Setup a ReactVChart with a Bar chart and DataZoom. +2. Provide an initial dataset. +3. Trigger a data update (e.g., via `setState`). +4. Observe that the chart updates. +5. **Verify**: The DataZoom preview should reflect the new data distribution. +6. **Verify**: Dragging the DataZoom handlers should correctly filter the _new_ data, not the old data. + +**Acceptance Scenarios**: + +1. **Given** a chart with DataZoom and initial data A, **When** the data is replaced with data B (different range/values), **Then** the DataZoom preview must re-render to show the shape of data B. +2. **Given** the data has been updated to data B, **When** I interact with the DataZoom, **Then** it should filter data B correctly. +3. **Given** a DataZoom spec with explicit range (e.g., start: 0, end: 0.2), **When** data or spec updates, **Then** the DataZoom range should respect the configured values (resetting to 0-0.2) rather than preserving current user interaction state or resetting to full range (0-1). + +--- + +### Edge Cases + +- **Data View Reference**: In React, props update might cause the underlying `DataView` to be replaced. DataZoom needs to unbind from the old `DataView` and bind to the new one. +- **Empty Data**: Updating to empty data should clear the preview safely. +- **User Interaction vs. Spec Reset**: If the user has manually panned the zoom, but then triggers a data update _without_ changing the spec range, should we preserve the manual position? + - _Clarification Answer implies_: If the spec contains explicit range settings passed down during update, those take precedence. If no specific range is enforced in the update payload, standard behavior applies (usually preserving if possible, or resetting if data is totally new). For this fix, we prioritize respecting the incoming spec configuration. + +## Requirements _(mandatory)_ + +### Functional Requirements + +- **FR-001**: `DataFilterBaseComponent` (and subclasses like `DataZoom`) MUST detect when the associated Series' data source (DataView) changes. +- **FR-002**: Upon detection of a data source change, the component MUST remove listeners from the old DataView to prevent memory leaks and stale updates. +- **FR-003**: The component MUST add listeners to the new DataView to receive `change` events. +- **FR-004**: The component MUST trigger a re-computation of its domain and re-render the preview when the data source changes. +- **FR-005**: On data/spec update, the DataZoom range (start/end) MUST be re-evaluated against the provided configuration. If `start`/`end` properties are present in the spec, they MUST be applied, overriding previous interactive states if they differ. + +### Key Entities + +- **DataFilterBaseComponent**: The base class for data filtering components. +- **DataView**: The VDataset object holding the data. +- **Series**: The chart series that provides the data to the DataZoom. + +## Success Criteria _(mandatory)_ + +### Measurable Outcomes + +- **SC-001**: DataZoom updates correctly (preview and filtering) 100% of the time after a data prop update in ReactVChart. +- **SC-002**: No errors in console regarding detached DataViews or stale listeners. +- **SC-003**: Explicit range configurations (start/end) are correctly applied after data updates. diff --git a/specs/007-fix-datazoom-react/tasks.md b/specs/007-fix-datazoom-react/tasks.md new file mode 100644 index 0000000000..84de844ed4 --- /dev/null +++ b/specs/007-fix-datazoom-react/tasks.md @@ -0,0 +1,95 @@ +--- +description: 'Task list template for feature implementation' +--- + +# Tasks: Fix DataZoom Value Update on Data Change in React + +**Input**: Design documents from `/specs/007-fix-datazoom-react/` +**Prerequisites**: plan.md (required), spec.md (required for user stories) + +**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story. + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (different files, no dependencies) +- **[Story]**: Which user story this task belongs to (e.g., US1) +- Include exact file paths in descriptions + No critical ambiguities detected worth formal clarification. The specification for this bug fix is quite focused and clear. However, there is one UX behavior that could be clarified regarding state persistence during updates. + +Recommended: Option A - Reset to full range (start: 0, end: 1) Reasoning : When the entire dataset is replaced (common in React data prop updates), the previous zoom window often becomes irrelevant. Resetting ensures the user sees the full context of the new data immediately. + +Option Description A Reset to full range (start: 0, end: 1). Safest for significant data changes. B Preserve relative percentage (e.g., keep 10%-20%). Good for streaming data, but risky if data distribution changes wildly. C Preserve absolute values . Try to keep the same axis values in view. Complex if new data doesn't overlap. + +You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer. + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Project initialization and basic structure + +- [ ] T001 Initialize React reproduction environment in packages/react-vchart/demo/src/BugReproduction.tsx +- [ ] T002 Update demo entry point in packages/react-vchart/demo/src/main.tsx + +--- + +## Phase 2: Foundational (Blocking Prerequisites) + +**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented + +_No new foundational infrastructure needed for this bug fix._ + +--- + +## Phase 3: User Story 1 - DataZoom Synchronization on Data Update (Priority: P1) 🎯 MVP + +**Goal**: Ensure DataZoom updates its range and preview when chart data changes, respecting user configuration. + +**Independent Test**: Run `npm run start` in `packages/react-vchart`, open demo, click "Update Data", verify DataZoom updates. + +### Implementation for User Story 1 + +- [ ] T003 [US1] Add `_collectDataInfo` helper method to packages/vchart/src/component/data-zoom/data-filter-base-component.ts +- [ ] T004 [US1] Add `_handleDataCollectionChangeBound` and `_currentDataCollection` properties to packages/vchart/src/component/data-zoom/data-filter-base-component.ts +- [ ] T005 [US1] Update `_initData` to track current data collection and bind listeners in packages/vchart/src/component/data-zoom/data-filter-base-component.ts +- [ ] T006 [US1] Implement `onDataUpdate` to detect data view changes and rebind listeners in packages/vchart/src/component/data-zoom/data-filter-base-component.ts +- [ ] T007 [US1] Update `onDataUpdate` to re-run data transforms and update state scale domain in packages/vchart/src/component/data-zoom/data-filter-base-component.ts +- [ ] T008 [US1] Ensure `onDataUpdate` respects explicit start/end spec configuration in packages/vchart/src/component/data-zoom/data-filter-base-component.ts + +**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently + +--- + +## Phase N: Polish & Cross-Cutting Concerns + +**Purpose**: Improvements that affect multiple user stories + +- [ ] T009 Clean up reproduction code in packages/react-vchart/demo/src/BugReproduction.tsx +- [ ] T010 Restore original demo entry point in packages/react-vchart/demo/src/main.tsx + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Setup (Phase 1)**: No dependencies - can start immediately +- **User Story 1 (Phase 3)**: Depends on Setup +- **Polish (Phase N)**: Depends on User Story 1 completion + +### Within User Story 1 + +- T003, T004 are prerequisites for T005 +- T005 is prerequisite for T006 +- T006, T007, T008 can be implemented sequentially in `onDataUpdate` + +### Parallel Opportunities + +- T003 and T004 can be implemented in parallel (different parts of class) + +## Implementation Strategy + +### MVP First (User Story 1 Only) + +1. Complete Phase 1: Setup reproduction +2. Complete Phase 3: Fix core logic in `DataFilterBaseComponent` +3. **STOP and VALIDATE**: Verify fix with reproduction +4. Complete Phase N: Cleanup