From e922211c03f5739bb78b482f5947dce91f61b0a0 Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Wed, 15 Jul 2026 13:15:36 +0800 Subject: [PATCH] fix: restore axis grid after visibility update --- ...ore-axis-grid-after-update_2026-07-15.json | 11 ++ .../unit/core/update-effects.test.ts | 105 ++++++++++++++++++ packages/vchart/src/mark/component.ts | 3 + 3 files changed, 119 insertions(+) create mode 100644 common/changes/@visactor/vchart/fix-restore-axis-grid-after-update_2026-07-15.json diff --git a/common/changes/@visactor/vchart/fix-restore-axis-grid-after-update_2026-07-15.json b/common/changes/@visactor/vchart/fix-restore-axis-grid-after-update_2026-07-15.json new file mode 100644 index 0000000000..a99dd9502e --- /dev/null +++ b/common/changes/@visactor/vchart/fix-restore-axis-grid-after-update_2026-07-15.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "fix: restore existing axis grid graphics when grid visibility is enabled again through updateSpec with animation disabled", + "type": "patch", + "packageName": "@visactor/vchart" + } + ], + "packageName": "@visactor/vchart", + "email": "lixuef1313@163.com" +} diff --git a/packages/vchart/__tests__/unit/core/update-effects.test.ts b/packages/vchart/__tests__/unit/core/update-effects.test.ts index 6fd4a2cff6..77feb011fa 100644 --- a/packages/vchart/__tests__/unit/core/update-effects.test.ts +++ b/packages/vchart/__tests__/unit/core/update-effects.test.ts @@ -40,6 +40,7 @@ type TestChartModel = { getComponentsByKey: (key: string) => Array<{ position?: string; getOrient?: () => string; + getVRenderComponents?: () => TestVRenderGraphic[]; getScale?: () => { domain: () => unknown[] }; getTickData?: () => { getDataView: () => { @@ -52,6 +53,15 @@ type TestChartModel = { reDataFlow: () => void; }; +type TestVRenderGraphic = { + name?: string; + attribute?: { + visible?: boolean; + visibleAll?: boolean; + }; + forEachChildren?: (cb: (child: TestVRenderGraphic) => void) => void; +}; + const getChartModel = (chart: VChart) => chart.getChart() as unknown as TestChartModel; const spyOnDataStages = (chart: VChart) => { @@ -261,6 +271,29 @@ const createAxisElementVisibleSpec = (element: AxisVisibleElement, visible: bool ] }); +const createLineAxisGridVisibleSpec = (gridVisible: boolean, animation: boolean): ILineChartSpec => + ({ + type: 'line', + animation, + data: [ + { + id: 'data', + values: [ + { x: 'A', y: 11 }, + { x: 'B', y: 12 }, + { x: 'C', y: 23 }, + { x: 'D', y: 14 } + ] + } + ], + xField: 'x', + yField: 'y', + axes: [ + { orient: 'left', grid: { visible: gridVisible } }, + { orient: 'bottom', grid: { visible: gridVisible } } + ] + } as ILineChartSpec); + const createLegendAppearanceSpec = ( labelFill: string, position: 'start' | 'middle' | 'end' = 'middle', @@ -1282,6 +1315,55 @@ const getAxisTickTransformOptions = (chart: VChart, orient: 'angle' | 'radius') return tickTransform?.options as { startAngle?: number }; }; +const findAxisGridComponent = (chart: VChart, orient: 'left' | 'bottom') => { + const axis = getChartModel(chart) + .getComponentsByKey('axes') + .find(axisItem => axisItem.getOrient?.() === orient); + + return axis?.getVRenderComponents?.()[1]; +}; + +const getAxisGridComponent = (chart: VChart, orient: 'left' | 'bottom') => { + const gridComponent = findAxisGridComponent(chart, orient); + expect(gridComponent).toBeDefined(); + + return gridComponent as TestVRenderGraphic; +}; + +const collectGraphicsByName = (graphic: TestVRenderGraphic, name: string) => { + const graphics: TestVRenderGraphic[] = []; + const visit = (current: TestVRenderGraphic) => { + if (current.name === name) { + graphics.push(current); + } + current.forEachChildren?.(visit); + }; + + visit(graphic); + return graphics; +}; + +const expectAxisGridLinesShown = (chart: VChart, orient: 'left' | 'bottom') => { + const gridComponent = getAxisGridComponent(chart, orient); + const gridLines = collectGraphicsByName(gridComponent, 'axis-grid-line'); + + expect(gridComponent.attribute?.visibleAll).not.toBe(false); + expect(gridLines.length).toBeGreaterThan(0); + gridLines.forEach(gridLine => { + expect(gridLine.attribute?.visible).not.toBe(false); + }); +}; + +const expectAxisGridHidden = (chart: VChart, orient: 'left' | 'bottom') => { + const gridComponent = findAxisGridComponent(chart, orient); + + if (!gridComponent) { + return; + } + + expect(gridComponent.attribute?.visibleAll).toBe(false); +}; + const getFirstScatterGraphic = (chart: VChart) => { const scatterSeries = chart .getChart() @@ -2196,6 +2278,29 @@ describe('vchart scoped update effects', () => { } }); + it('restores existing axis grid lines after animation false hides and shows them', async () => { + const chart = new VChart(createLineAxisGridVisibleSpec(true, true), { dom }); + + try { + chart.renderSync(); + + expectAxisGridLinesShown(chart, 'left'); + expectAxisGridLinesShown(chart, 'bottom'); + + await chart.updateSpec(createLineAxisGridVisibleSpec(false, false)); + + expectAxisGridHidden(chart, 'left'); + expectAxisGridHidden(chart, 'bottom'); + + await chart.updateSpec(createLineAxisGridVisibleSpec(true, false)); + + expectAxisGridLinesShown(chart, 'left'); + expectAxisGridLinesShown(chart, 'bottom'); + } finally { + chart.release(); + } + }); + it('keeps axis min max updates on the series data path', () => { const chart = new VChart(createAxisAppearanceSpec(), { dom, animation: false }); diff --git a/packages/vchart/src/mark/component.ts b/packages/vchart/src/mark/component.ts index b3596e4091..25c2c6db52 100644 --- a/packages/vchart/src/mark/component.ts +++ b/packages/vchart/src/mark/component.ts @@ -190,6 +190,9 @@ export class ComponentMark extends BaseMark implements IComponentMa this._component && this._product.appendChild(this._component); } else { this._component.setAttributes(attrs as any); + if (this._product && this._component.parent !== this._product) { + this._product.appendChild(this._component); + } } if (this._component) {