From e1d3089e9a96951dc2245c5a4251b344f39f2fed Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 20 Apr 2026 16:10:29 +0800 Subject: [PATCH 1/5] Revert "fix: relayout api not work bug. fix#4537" --- packages/vchart/src/core/vchart.ts | 6 +-- packages/vchart/src/series/map/map.ts | 40 +++---------------- packages/vchart/src/series/scatter/scatter.ts | 21 ++-------- 3 files changed, 11 insertions(+), 56 deletions(-) diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index ec12b23cac..a2be2649e7 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -1815,10 +1815,8 @@ export class VChart implements IVChart { * 强制重新布局 */ reLayout() { - this._chart?.resetLayoutItemTag(); - // Force immediate layout + render to ensure geo components reset roam state. - this._chart?.setLayoutTag(true, null, false); - this._compiler?.render(); + this._chart.resetLayoutItemTag(); + this._chart?.setLayoutTag(true); } /** diff --git a/packages/vchart/src/series/map/map.ts b/packages/vchart/src/series/map/map.ts index 4b2116d444..6fbc11206f 100644 --- a/packages/vchart/src/series/map/map.ts +++ b/packages/vchart/src/series/map/map.ts @@ -252,24 +252,10 @@ export class MapSeries extends GeoSer } pathGroup.scale(scale, scale, scaleCenter); } - const labelComponent = this._labelMark?.getComponent(); + const vgrammarLabel = this._labelMark?.getComponent(); - if (labelComponent?.renderInner) { - labelComponent.renderInner(); - } - const vgrammarLabel = labelComponent?.getComponent?.(); - if (vgrammarLabel?.evaluate) { - (vgrammarLabel as any).evaluate(null, null); - } - // 标签跟随地图 - const labelGroup = labelComponent?.getProduct?.(); - if (labelGroup && scale && scaleCenter) { - if (!labelGroup.attribute?.postMatrix) { - labelGroup.setAttributes({ - postMatrix: new Matrix() - }); - } - labelGroup.scale(scale, scale, scaleCenter); + if (vgrammarLabel) { + vgrammarLabel.renderInner(); } } @@ -287,24 +273,10 @@ export class MapSeries extends GeoSer } pathGroup.translate(delta[0], delta[1]); } - const labelComponent = this._labelMark?.getComponent(); + const vgrammarLabel = this._labelMark?.getComponent(); - if (labelComponent?.renderInner) { - labelComponent.renderInner(); - } - const vgrammarLabel = labelComponent?.getComponent?.(); - if (vgrammarLabel?.evaluate) { - (vgrammarLabel as any).evaluate(null, null); - } - // 标签跟随地图 - const labelGroup = labelComponent?.getProduct?.(); - if (labelGroup && delta) { - if (!labelGroup.attribute?.postMatrix) { - labelGroup.setAttributes({ - postMatrix: new Matrix() - }); - } - labelGroup.translate(delta[0], delta[1]); + if (vgrammarLabel) { + vgrammarLabel.renderInner(); } } diff --git a/packages/vchart/src/series/scatter/scatter.ts b/packages/vchart/src/series/scatter/scatter.ts index 9f41789512..6bed93e99e 100644 --- a/packages/vchart/src/series/scatter/scatter.ts +++ b/packages/vchart/src/series/scatter/scatter.ts @@ -4,7 +4,7 @@ import type { DataView } from '@visactor/vdataset'; import type { Datum, ScaleType, VisualType, IScatterInvalidType } from '../../typings'; import type { IScatterSeriesSpec, ScatterAppearPreset } from './interface'; import { CartesianSeries } from '../cartesian/cartesian'; -import { isNil, isValid, isObject, isFunction, isString, isArray, isNumber, isNumeric, Matrix } from '@visactor/vutils'; +import { isNil, isValid, isObject, isFunction, isString, isArray, isNumber, isNumeric } from '@visactor/vutils'; import { AttributeLevel } from '../../constant/attribute'; import type { SeriesMarkMap } from '../interface'; import { SeriesMarkNameEnum, SeriesTypeEnum } from '../interface/type'; @@ -370,26 +370,11 @@ export class ScatterSeries ex }); }); - const labelComponent = this._labelMark?.getComponent(); + const vgrammarLabel = this._labelMark?.getComponent()?.getProduct(); - if (labelComponent?.renderInner) { - labelComponent.renderInner(); - } - const vgrammarLabel = labelComponent?.getComponent?.(); - if (vgrammarLabel?.evaluate) { + if (vgrammarLabel) { (vgrammarLabel as any).evaluate(null, null); } - - // 标签跟随地图 - const labelGroup = labelComponent?.getProduct?.(); - if (labelGroup && e?.scale && e?.scaleCenter) { - if (!labelGroup.attribute?.postMatrix) { - labelGroup.setAttributes({ - postMatrix: new Matrix() - }); - } - labelGroup.scale(e.scale, e.scale, e.scaleCenter); - } } handlePan(e: any) { From e5d1a67319bed72c199dc137a9f7a5262f06946b Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 20 Apr 2026 16:33:13 +0800 Subject: [PATCH 2/5] fix: vchart relayout api not work bug. fix#4537 --- .../vchart/fix-map-bug_2026-04-20-08-30.json | 10 +++++ .../vchart/__tests__/unit/core/vchart.test.ts | 40 +++++++++++++++++++ packages/vchart/src/core/vchart.ts | 9 ++++- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-30.json diff --git a/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-30.json b/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-30.json new file mode 100644 index 0000000000..f74780a959 --- /dev/null +++ b/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-30.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "fix: vchart relayout api not work bug. fix#4537", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/__tests__/unit/core/vchart.test.ts b/packages/vchart/__tests__/unit/core/vchart.test.ts index 7f0f2b05c7..c31a5dbdc1 100644 --- a/packages/vchart/__tests__/unit/core/vchart.test.ts +++ b/packages/vchart/__tests__/unit/core/vchart.test.ts @@ -299,6 +299,46 @@ describe('VChart', () => { expect((labels.children[3] as Text).attribute.fillOpacity).toBe(1); expect((labels.children[3] as Text).attribute.text).toBe(1200); }); + + it('reLayout', () => { + const spec: IBarChartSpec = { + type: 'bar', + width: 200, + height: 150, + data: [ + { + id: 'data', + values: [ + { x: 'Mon', y: 100 }, + { x: 'Tue', y: 66 } + ] + } + ], + xField: 'x', + yField: 'y', + axes: [{ orient: 'bottom', type: 'band' }, { orient: 'left' }] + }; + + vchart = new VChart(spec, { + renderCanvas: canvasDom, + animation: false + }); + vchart.renderSync(); + + const chart = vchart.getChart(); + const compiler = vchart.getCompiler(); + const resetLayoutItemTagSpy = jest.spyOn(chart, 'resetLayoutItemTag'); + const setLayoutTagSpy = jest.spyOn(chart, 'setLayoutTag'); + const renderSpy = jest.spyOn(compiler, 'render'); + const onEvaluateEndSpy = jest.spyOn(chart, 'onEvaluateEnd'); + + vchart.reLayout(); + + expect(resetLayoutItemTagSpy).toHaveBeenCalledTimes(1); + expect(setLayoutTagSpy).toHaveBeenCalledWith(true, null, false); + expect(renderSpy).toHaveBeenCalledTimes(1); + expect(onEvaluateEndSpy).toHaveBeenCalledTimes(1); + }); }); describe('convertDatumToPosition and convertValueToPosition', () => { diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index a2be2649e7..7471f449fc 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -1815,8 +1815,15 @@ export class VChart implements IVChart { * 强制重新布局 */ reLayout() { + if (!this._chart || !this._compiler || this._isReleased) { + return; + } this._chart.resetLayoutItemTag(); - this._chart?.setLayoutTag(true); + this._chart.setLayoutTag(true, null, false); + this._compiler.render(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this._chart.onEvaluateEnd(); } /** From 153506a542be94db4f34eb7290ea32049e1fed0b Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 20 Apr 2026 16:58:43 +0800 Subject: [PATCH 3/5] fix: label not follow when drag. fix#4547 --- .../vchart/fix-map-bug_2026-04-20-08-58.json | 10 ++++ packages/vchart/src/series/scatter/scatter.ts | 48 ++++++++++++------- 2 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-58.json diff --git a/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-58.json b/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-58.json new file mode 100644 index 0000000000..e15c40e64c --- /dev/null +++ b/common/changes/@visactor/vchart/fix-map-bug_2026-04-20-08-58.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "fix: label not follow when drag. fix#4547", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/series/scatter/scatter.ts b/packages/vchart/src/series/scatter/scatter.ts index 6bed93e99e..97661a72d0 100644 --- a/packages/vchart/src/series/scatter/scatter.ts +++ b/packages/vchart/src/series/scatter/scatter.ts @@ -28,6 +28,7 @@ import { ScatterSeriesSpecTransformer } from './scatter-transformer'; import { getGroupAnimationParams } from '../util/utils'; import { registerCartesianLinearAxis, registerCartesianBandAxis } from '../../component/axis/cartesian'; import { scatter } from '../../theme/builtin/common/series/scatter'; +import type { IGraphic } from '@visactor/vrender-core'; export class ScatterSeries extends CartesianSeries { static readonly type: string = SeriesTypeEnum.scatter; @@ -351,35 +352,48 @@ export class ScatterSeries ex * 处理缩放 */ handleZoom(e: any) { - this.getMarksWithoutRoot().forEach(mark => { - if (!mark) { - return; - } - const graphics = mark.getGraphics(); - - if (!graphics || !graphics.length) { - return; - } + const graphics = this._symbolMark?.getGraphics(); - graphics.forEach((graphicItem: IMarkGraphic, i: number) => { + if (graphics && graphics.length) { + graphics.forEach((graphicItem: IMarkGraphic) => { const datum = graphicItem?.context?.data?.[0]; const newPosition = this.dataToPosition(datum); if (newPosition && graphicItem) { - graphicItem.translateTo(newPosition.x, newPosition.y); + (graphicItem as unknown as IGraphic).translateTo(newPosition.x, newPosition.y); } }); - }); + } - const vgrammarLabel = this._labelMark?.getComponent()?.getProduct(); + const labelComponent = this._labelMark?.getComponent(); - if (vgrammarLabel) { - (vgrammarLabel as any).evaluate(null, null); + if (labelComponent) { + labelComponent.renderInner(); } } handlePan(e: any) { - // TODO 现在处理好像一模一样 - this.handleZoom(e); + const { delta } = e; + if (delta?.[0] === 0 && delta?.[1] === 0) { + return; + } + + const graphics = this._symbolMark?.getGraphics(); + + if (graphics && graphics.length) { + graphics.forEach((graphicItem: IMarkGraphic) => { + const datum = graphicItem?.context?.data?.[0]; + const newPosition = this.dataToPosition(datum); + if (newPosition && graphicItem) { + (graphicItem as IMarkGraphic).translateTo(newPosition.x, newPosition.y); + } + }); + } + + const labelGraphic = this._labelMark?.getComponent()?.getComponent(); + + if (labelGraphic) { + labelGraphic.translate(delta[0], delta[1]); + } } getDefaultShapeType() { From b605678c25581f57a0c093c4f26b1f086da892ba Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 20 Apr 2026 17:20:44 +0800 Subject: [PATCH 4/5] fix: label not follow when zoom. fix#4547 --- packages/vchart/src/series/scatter/scatter.ts | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/vchart/src/series/scatter/scatter.ts b/packages/vchart/src/series/scatter/scatter.ts index 97661a72d0..887c0b8c93 100644 --- a/packages/vchart/src/series/scatter/scatter.ts +++ b/packages/vchart/src/series/scatter/scatter.ts @@ -4,7 +4,7 @@ import type { DataView } from '@visactor/vdataset'; import type { Datum, ScaleType, VisualType, IScatterInvalidType } from '../../typings'; import type { IScatterSeriesSpec, ScatterAppearPreset } from './interface'; import { CartesianSeries } from '../cartesian/cartesian'; -import { isNil, isValid, isObject, isFunction, isString, isArray, isNumber, isNumeric } from '@visactor/vutils'; +import { isNil, isValid, isObject, isFunction, isString, isArray, isNumber, isNumeric, Matrix } from '@visactor/vutils'; import { AttributeLevel } from '../../constant/attribute'; import type { SeriesMarkMap } from '../interface'; import { SeriesMarkNameEnum, SeriesTypeEnum } from '../interface/type'; @@ -351,23 +351,49 @@ export class ScatterSeries ex /** * 处理缩放 */ - handleZoom(e: any) { + private _updateSymbolGraphicPosition() { const graphics = this._symbolMark?.getGraphics(); - if (graphics && graphics.length) { - graphics.forEach((graphicItem: IMarkGraphic) => { - const datum = graphicItem?.context?.data?.[0]; - const newPosition = this.dataToPosition(datum); - if (newPosition && graphicItem) { - (graphicItem as unknown as IGraphic).translateTo(newPosition.x, newPosition.y); - } + if (!graphics || !graphics.length) { + return; + } + + graphics.forEach((graphicItem: IMarkGraphic) => { + const datum = graphicItem?.context?.data?.[0]; + const newPosition = this.dataToPosition(datum); + if (newPosition && graphicItem) { + (graphicItem as unknown as IGraphic).setAttributes({ + x: newPosition.x, + y: newPosition.y + }); + } + }); + } + + private _ensureLabelGraphicPostMatrix() { + const labelGraphic = this._labelMark?.getComponent()?.getComponent(); + + if (labelGraphic && !labelGraphic.attribute.postMatrix) { + labelGraphic.setAttributes({ + postMatrix: new Matrix() }); } - const labelComponent = this._labelMark?.getComponent(); + return labelGraphic; + } + + handleZoom(e: any) { + const { scale, scaleCenter } = e; + if (scale === 1) { + return; + } + + this._updateSymbolGraphicPosition(); + + const labelGraphic = this._ensureLabelGraphicPostMatrix(); - if (labelComponent) { - labelComponent.renderInner(); + if (labelGraphic) { + labelGraphic.scale(scale, scale, scaleCenter); } } @@ -377,19 +403,9 @@ export class ScatterSeries ex return; } - const graphics = this._symbolMark?.getGraphics(); + this._updateSymbolGraphicPosition(); - if (graphics && graphics.length) { - graphics.forEach((graphicItem: IMarkGraphic) => { - const datum = graphicItem?.context?.data?.[0]; - const newPosition = this.dataToPosition(datum); - if (newPosition && graphicItem) { - (graphicItem as IMarkGraphic).translateTo(newPosition.x, newPosition.y); - } - }); - } - - const labelGraphic = this._labelMark?.getComponent()?.getComponent(); + const labelGraphic = this._ensureLabelGraphicPostMatrix(); if (labelGraphic) { labelGraphic.translate(delta[0], delta[1]); From 602033096a0bd10cbbbdeb85ab74d191c51977d2 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Tue, 21 Apr 2026 20:41:51 +0800 Subject: [PATCH 5/5] fix: scatter and label not relayout when set relayout api --- packages/vchart/src/series/scatter/scatter.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/vchart/src/series/scatter/scatter.ts b/packages/vchart/src/series/scatter/scatter.ts index 887c0b8c93..7ac4988754 100644 --- a/packages/vchart/src/series/scatter/scatter.ts +++ b/packages/vchart/src/series/scatter/scatter.ts @@ -412,6 +412,23 @@ export class ScatterSeries ex } } + onLayoutEnd(): void { + super.onLayoutEnd(); + this._updateSymbolGraphicPosition(); + + const labelGraphic = this._labelMark?.getComponent()?.getComponent(); + if (labelGraphic?.attribute.postMatrix) { + labelGraphic.setAttributes({ + postMatrix: new Matrix() + }); + } + + const vgrammarLabel = this._labelMark?.getComponent(); + if (vgrammarLabel) { + vgrammarLabel.renderInner(); + } + } + getDefaultShapeType() { return 'circle'; }