Skip to content

Commit 7f3d952

Browse files
authored
Merge branch 'develop' into 008-fix-size-legend-handler-text
2 parents 6fe998a + cc3c46f commit 7f3d952

28 files changed

Lines changed: 765 additions & 54 deletions

File tree

.cursor/commands/speckit.prgenerate.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
description: 'Generate a PR body using the GitHub pull request template and specs/<spec-id>/plan.md; default to the English template and write to specs/<spec-id>/PR_BODY.md.'
2+
description: 'Generate a PR body using the GitHub pull request template and specs/<spec-id>/plan.md; default to the English template and write to .trae/output/pr.body.local.md.'
33
handoffs:
44
- label: 'Create Pull Request'
55
agent: 'speckit.prcreate'
@@ -22,7 +22,7 @@ You **MUST** consider the user input before proceeding (if not empty), but treat
2222
- Parse `$ARGUMENTS` only for CLI-style options (for example, `--lang`, `--out`):
2323
- If `--lang zh` is present, use the Chinese template at `.github/PULL_REQUEST_TEMPLATE/pr_cn.md`.
2424
- Otherwise, use the English template at `.github/PULL_REQUEST_TEMPLATE.md` (the default; **do not** auto-detect language).
25-
- If an explicit output path is provided (for example, `--out specs/001-foo/PR_BODY.md`), respect it; otherwise, default to `specs/<spec-id>/PR_BODY.md`.
25+
- If an explicit output path is provided (for example, `--out specs/001-foo/PR_BODY.md`), respect it; otherwise, default to `.trae/output/pr.body.local.md`.
2626
- Resolve `specs/<spec-id>/` by deriving the numeric prefix from the current branch name and matching it to a directory under `specs/` whose name starts with that prefix.
2727
- From that directory, resolve `plan.md` as the primary context source for the PR.
2828

@@ -61,7 +61,7 @@ You **MUST** consider the user input before proceeding (if not empty), but treat
6161

6262
6. **Write PR body file without touching templates**:
6363
- Render the updated markdown content (with checklist, background, and Changelog injected) into a single PR body string.
64-
- Write this string to the resolved output path (default `specs/<spec-id>/PR_BODY.md`), creating parent directories if needed.
64+
- Write this string to the resolved output path (default `.trae/output/pr.body.local.md`), creating parent directories if needed.
6565
- Do **not** modify the original template files under `.github/`.
6666

6767
7. **Validation checklist**:

.cursor/rules/specify-rules.mdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Auto-generated from all feature plans. Last updated: 2026-01-15
66
- TypeScript 4.x+ (Project uses TS) + `@visactor/vchart` (Core logic), `@visactor/react-vchart` (React wrapper) (007-fix-datazoom-react)
77
- N/A (In-memory chart state) (007-fix-datazoom-react)
88
- Markdown + JSON(文档内容与菜单配置) + `@internal/docs` 文档构建体系、`docs/assets/guide/menu.json` 导航配置、现有教程目录结构 (001-vchart-skill-tutorial)
9-
- TypeScript 4.9.x + `@visactor/vutils`, `@visactor/vutils-extension`, `@visactor/vrender-components` (008-fix-size-legend-handler-text)
9+
- TypeScript 4.9.5 + `@visactor/vchart`, `@visactor/vutils`, `@visactor/vrender-components` (010-hide-empty-axes)
1010

1111
- TypeScript/React 18 + @visactor/react-vchart, @visactor/vchar (001-react-vchart-demo)
1212

@@ -28,7 +28,7 @@ npm test && npm run lint
2828
TypeScript 4.9.5: Follow standard conventions
2929

3030
## Recent Changes
31-
- 008-fix-size-legend-handler-text: Added TypeScript 4.9.x + `@visactor/vutils`, `@visactor/vutils-extension`, `@visactor/vrender-components`
31+
- 010-hide-empty-axes: Added TypeScript 4.9.5 + `@visactor/vchart`, `@visactor/vutils`, `@visactor/vrender-components`
3232
- 001-vchart-skill-tutorial: Added Markdown + JSON(文档内容与菜单配置) + `@internal/docs` 文档构建体系、`docs/assets/guide/menu.json` 导航配置、现有教程目录结构
3333
- 007-fix-datazoom-react: Added TypeScript 4.x+ (Project uses TS) + `@visactor/vchart` (Core logic), `@visactor/react-vchart` (React wrapper)
3434

.vscode/launch.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,27 @@
1616
"skipFiles": ["<node_internals>/**"],
1717
"type": "pwa-node"
1818
},
19+
{
20+
"name": "Debug Jest-Electron Current File",
21+
"type": "node",
22+
"request": "launch",
23+
"cwd": "${workspaceFolder}/packages/vchart",
24+
"program": "${workspaceFolder}/packages/vchart/node_modules/jest/bin/jest.js",
25+
"args": [
26+
"${file}",
27+
"--watch"
28+
],
29+
"env": {
30+
"DEBUG_MODE": "1"
31+
},
32+
"console": "integratedTerminal",
33+
"internalConsoleOptions": "neverOpen"
34+
},
1935
{
2036
"name": "unit test",
2137
"type": "pwa-node",
2238
"request": "launch",
23-
"program": "${workspaceFolder}/packages/vchart/node_modules/.bin/jest",
39+
"program": "${workspaceFolder}/packages/vchart/node_modules/jest/bin/jest.js",
2440
"args": ["${file}"],
2541
"console": "integratedTerminal",
2642
"internalConsoleOptions": "neverOpen"
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 010-hide-empty-axes: Add an opt-in hideWhenEmpty axis option for cartesian axes.",
5+
"type": "none",
6+
"packageName": "@visactor/vchart"
7+
}
8+
],
9+
"packageName": "@visactor/vchart",
10+
"email": "lixuef1313@163.com"
11+
}
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-issue-of-mark-state-when-updateSpec: Fix an issue where mark states were not properly cleared when updateSpec was called, causing incorrect state persistence.",
5+
"type": "none",
6+
"packageName": "@visactor/vchart"
7+
}
8+
],
9+
"packageName": "@visactor/vchart",
10+
"email": "lixuef1313@163.com"
11+
}

packages/vchart-types/types/component/axis/cartesian/interface/spec.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type ICartesianZ = {
2121
orient: 'z';
2222
};
2323
export type ICartesianAxisCommonSpec = ICommonAxisSpec & {
24+
hideWhenEmpty?: boolean;
2425
grid?: IGrid;
2526
subGrid?: IGrid;
2627
domainLine?: ICartesianDomainLine;
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { default as VChartConstructor } from '../../../../../src';
2+
import { createCanvas, removeDom } from '../../../../util/dom';
3+
4+
describe('cartesian axis hideWhenEmpty', () => {
5+
let canvasDom: HTMLCanvasElement;
6+
let vchart: any;
7+
8+
beforeEach(() => {
9+
canvasDom = createCanvas();
10+
canvasDom.style.position = 'relative';
11+
canvasDom.style.width = '500px';
12+
canvasDom.style.height = '500px';
13+
canvasDom.width = 500;
14+
canvasDom.height = 500;
15+
});
16+
17+
afterEach(() => {
18+
removeDom(canvasDom);
19+
vchart?.release();
20+
});
21+
22+
const getAxis = (orient: string) =>
23+
vchart.getComponents().find((com: any) => com.layout?.layoutOrient === orient) as any;
24+
25+
test('should hide axis on initial render when bound series has no collected data', () => {
26+
vchart = new VChartConstructor(
27+
{
28+
type: 'line',
29+
width: 400,
30+
height: 300,
31+
data: [{ id: 'lineData', values: [] }],
32+
axes: [
33+
{ id: 'axis-left', orient: 'left', hideWhenEmpty: true },
34+
{ id: 'axis-bottom', orient: 'bottom', type: 'band' }
35+
],
36+
series: [{ type: 'line', dataId: 'lineData', xField: 'x', yField: 'y' }]
37+
} as any,
38+
{
39+
renderCanvas: canvasDom,
40+
animation: false
41+
}
42+
);
43+
44+
vchart.renderSync();
45+
46+
const leftAxis = getAxis('left');
47+
expect(leftAxis.getVisible()).toBe(false);
48+
expect(leftAxis.getLayoutRect().width).toBe(0);
49+
});
50+
51+
test('should keep default behavior when hideWhenEmpty is not enabled', () => {
52+
vchart = new VChartConstructor(
53+
{
54+
type: 'line',
55+
width: 400,
56+
height: 300,
57+
data: [{ id: 'lineData', values: [] }],
58+
axes: [
59+
{ id: 'axis-left', orient: 'left' },
60+
{ id: 'axis-bottom', orient: 'bottom', type: 'band' }
61+
],
62+
series: [{ type: 'line', dataId: 'lineData', xField: 'x', yField: 'y' }]
63+
} as any,
64+
{
65+
renderCanvas: canvasDom,
66+
animation: false
67+
}
68+
);
69+
70+
vchart.renderSync();
71+
72+
const leftAxis = getAxis('left');
73+
expect(leftAxis.getVisible()).toBe(true);
74+
});
75+
76+
test('should only hide empty bound axes and show them again after data updates', async () => {
77+
vchart = new VChartConstructor(
78+
{
79+
type: 'common',
80+
width: 400,
81+
height: 300,
82+
data: [
83+
{ id: 'emptyLine', values: [] },
84+
{
85+
id: 'activeLine',
86+
values: [
87+
{ x: 'Mon', y: 10 },
88+
{ x: 'Tue', y: 20 }
89+
]
90+
}
91+
],
92+
axes: [
93+
{ id: 'axis-left', orient: 'left', seriesIndex: [0], hideWhenEmpty: true },
94+
{ id: 'axis-right', orient: 'right', seriesIndex: [1], hideWhenEmpty: true },
95+
{ id: 'axis-bottom', orient: 'bottom', type: 'band' }
96+
],
97+
series: [
98+
{ type: 'line', dataId: 'emptyLine', xField: 'x', yField: 'y' },
99+
{ type: 'line', dataId: 'activeLine', xField: 'x', yField: 'y' }
100+
]
101+
} as any,
102+
{
103+
renderCanvas: canvasDom,
104+
animation: false
105+
}
106+
);
107+
108+
vchart.renderSync();
109+
110+
const leftAxis = getAxis('left');
111+
const rightAxis = getAxis('right');
112+
expect(leftAxis.getVisible()).toBe(false);
113+
expect(rightAxis.getVisible()).toBe(true);
114+
115+
await vchart.updateData('emptyLine', [
116+
{ x: 'Mon', y: 5 },
117+
{ x: 'Tue', y: 15 }
118+
]);
119+
120+
expect(leftAxis.getVisible()).toBe(true);
121+
expect(leftAxis.getLayoutRect().width).toBeGreaterThan(0);
122+
});
123+
});

packages/vchart/src/compile/mark/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface IMarkStateManager {
6464
addStateInfo: (stateInfo: IStateInfo) => void;
6565
changeStateInfo: (stateInfo: Partial<IStateInfo>) => void;
6666
clearStateInfo: (stateValues: StateValue[]) => void;
67+
clearAllStateInfo: () => void;
6768
checkOneState: (renderNode: IMarkGraphic, datum: Datum[], state: IStateInfo) => 'in' | 'out' | 'skip';
6869
checkState: (renderNode: IMarkGraphic, datum: Datum[]) => StateValue[];
6970
getStateMap: () => StateValueMap;

packages/vchart/src/compile/mark/mark-state-manager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ export class MarkStateManager extends StateManager implements IMarkStateManager
123123
});
124124
}
125125

126+
clearAllStateInfo() {
127+
this._stateInfoList = [];
128+
}
129+
126130
protected _isMultiMark() {
127131
return !this._mark || isMultiDatumMark(this._mark.type as MarkTypeEnum);
128132
}

0 commit comments

Comments
 (0)