From bfac29f0adc54513f30c3b54ae0dda04a2f874a7 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Sun, 4 Jan 2026 20:05:15 +0800 Subject: [PATCH 1/9] feat: add brush api before change --- .../feat-brush-api_2026-01-04-12-02.json | 10 +++++++ packages/vchart/src/component/brush/brush.ts | 26 ++++++++++--------- .../vchart/src/component/brush/interface.ts | 7 ++++- 3 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 common/changes/@visactor/vchart/feat-brush-api_2026-01-04-12-02.json diff --git a/common/changes/@visactor/vchart/feat-brush-api_2026-01-04-12-02.json b/common/changes/@visactor/vchart/feat-brush-api_2026-01-04-12-02.json new file mode 100644 index 0000000000..9b9944b4b5 --- /dev/null +++ b/common/changes/@visactor/vchart/feat-brush-api_2026-01-04-12-02.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: add brush api before change", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/component/brush/brush.ts b/packages/vchart/src/component/brush/brush.ts index 5ee7fa599b..831eea62ae 100644 --- a/packages/vchart/src/component/brush/brush.ts +++ b/packages/vchart/src/component/brush/brush.ts @@ -257,6 +257,7 @@ export class Brush extends BaseComponent i ...interactiveAttr, ...this._spec, disableTriggerEvent: this._option.disableTriggerEvent + // beforeBrushChange: this._spec.beforeBrushChange }); brush.id = this._spec.id ?? `brush-${this.id}`; this.getContainer().add(brush as unknown as INode); @@ -265,35 +266,35 @@ export class Brush extends BaseComponent i brush.addEventListener(BrushEvent.brushActive, (e: any) => { this._initMarkBrushState(componentIndex, OUT_BRUSH_STATE); - this._emitEvent(ChartEvent.brushActive, region); + this._emitEvent(ChartEvent.brushActive, region, e); }); brush.addEventListener(BrushEvent.drawStart, (e: any) => { this._setRegionMarkPickable(region, true); - this._emitEvent(ChartEvent.brushStart, region); + this._emitEvent(ChartEvent.brushStart, region, e); }); brush.addEventListener(BrushEvent.moveStart, (e: any) => { this._setRegionMarkPickable(region, true); - this._emitEvent(ChartEvent.brushStart, region); + this._emitEvent(ChartEvent.brushStart, region, e); }); brush.addEventListener(BrushEvent.drawing, (e: any) => { this._setRegionMarkPickable(region, false); this._handleBrushChange(region, e); - this._emitEvent(ChartEvent.brushChange, region); + this._emitEvent(ChartEvent.brushChange, region, e); }); brush.addEventListener(BrushEvent.moving, (e: any) => { this._setRegionMarkPickable(region, false); this._handleBrushChange(region, e); - this._emitEvent(ChartEvent.brushChange, region); + this._emitEvent(ChartEvent.brushChange, region, e); }); brush.addEventListener(BrushEvent.brushClear, (e: any) => { this._setRegionMarkPickable(region, true); this._initMarkBrushState(componentIndex, ''); - this._emitEvent(ChartEvent.brushClear, region); + this._emitEvent(ChartEvent.brushClear, region, e); }); brush.addEventListener(BrushEvent.drawEnd, (e: any) => { @@ -305,17 +306,17 @@ export class Brush extends BaseComponent i if (this._spec.onBrushEnd(e) === true) { this.clearGraphic(); this._initMarkBrushState(componentIndex, ''); - this._emitEvent(ChartEvent.brushClear, region); + this._emitEvent(ChartEvent.brushClear, region, e); } else { this._spec.onBrushEnd(e); - this._emitEvent(ChartEvent.brushEnd, region); + this._emitEvent(ChartEvent.brushEnd, region, e); } } else { const inBrushData = this._extendDataInBrush(this._inBrushElementsMap); if ((!this._spec.zoomWhenEmpty && inBrushData.length > 0) || !updateElementsState) { this._setAxisAndDataZoom(operateMask, region); } - this._emitEvent(ChartEvent.brushEnd, region); + this._emitEvent(ChartEvent.brushEnd, region, e); } }); @@ -327,7 +328,7 @@ export class Brush extends BaseComponent i if ((!this._spec.zoomWhenEmpty && inBrushData.length > 0) || updateElementsState) { this._setAxisAndDataZoom(operateMask, region); } - this._emitEvent(ChartEvent.brushEnd, region); + this._emitEvent(ChartEvent.brushEnd, region, e); }); } @@ -403,7 +404,7 @@ export class Brush extends BaseComponent i return data; } - private _emitEvent(eventType: string, region: IRegion) { + private _emitEvent(eventType: string, region: IRegion, e: any) { this.event.emit(eventType, { model: this, value: { @@ -430,7 +431,8 @@ export class Brush extends BaseComponent i // 缩放记录 zoomRecord: this._zoomRecord }, - vchart: this._option?.globalInstance + vchart: this._option?.globalInstance, + event: e }); } /*** end: event dispatch ***/ diff --git a/packages/vchart/src/component/brush/interface.ts b/packages/vchart/src/component/brush/interface.ts index dec799be6d..5ff1e12510 100644 --- a/packages/vchart/src/component/brush/interface.ts +++ b/packages/vchart/src/component/brush/interface.ts @@ -1,4 +1,4 @@ -import type { SymbolType } from '@visactor/vrender-core'; +import type { FederatedPointerEvent, SymbolType } from '@visactor/vrender-core'; import type { IPolygonMarkSpec } from '../../typings'; import type { IComponent } from '../interface'; import type { IDelayType } from '../../typings/event'; @@ -65,6 +65,11 @@ interface IBrushDataBindSpec { * 2) 散点图按照散点中心定位, 如果严格按照中心范围更新,会出现散点超出画布的现象 */ axisRangeExpand?: number; + /** + * 框选前触发事件 + * 返回false, 则阻止后续逻辑 + */ + beforeBrushChange?: (e: FederatedPointerEvent) => void | boolean; } export interface IBrushTheme { From d153507582ca49e587ec06cbd309d5313c3fc1b4 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 5 Jan 2026 17:41:56 +0800 Subject: [PATCH 2/9] feat: add interactive api --- .../vchart/feat-brush-api_2026-01-05-09-41.json | 10 ++++++++++ packages/vchart/src/compile/compiler.ts | 7 +++++-- packages/vchart/src/component/brush/brush.ts | 14 +++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 common/changes/@visactor/vchart/feat-brush-api_2026-01-05-09-41.json diff --git a/common/changes/@visactor/vchart/feat-brush-api_2026-01-05-09-41.json b/common/changes/@visactor/vchart/feat-brush-api_2026-01-05-09-41.json new file mode 100644 index 0000000000..2f4c372c85 --- /dev/null +++ b/common/changes/@visactor/vchart/feat-brush-api_2026-01-05-09-41.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "git commit -m 'feat: add interactive api", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/compile/compiler.ts b/packages/vchart/src/compile/compiler.ts index ae7747b19a..6ae4edc2b2 100644 --- a/packages/vchart/src/compile/compiler.ts +++ b/packages/vchart/src/compile/compiler.ts @@ -71,6 +71,9 @@ export class Compiler implements ICompiler { protected _container: IRenderContainer; protected _option: IRenderOption; + getOption() { + return this._option; + } // 已释放标记 private _released: boolean = false; @@ -498,8 +501,8 @@ export class Compiler implements ICompiler { const animationState = markAnimationStates.every(state => state === AnimationStateEnum.appear) ? AnimationStateEnum.appear : markAnimationStates.every(state => state === AnimationStateEnum.disappear) - ? AnimationStateEnum.disappear - : AnimationStateEnum.none; + ? AnimationStateEnum.disappear + : AnimationStateEnum.none; if (!this._stage.context) { this._stage.context = {}; } diff --git a/packages/vchart/src/component/brush/brush.ts b/packages/vchart/src/component/brush/brush.ts index 831eea62ae..9a18421698 100644 --- a/packages/vchart/src/component/brush/brush.ts +++ b/packages/vchart/src/component/brush/brush.ts @@ -8,7 +8,7 @@ import { Brush as BrushComponent, IOperateType as BrushEvent } from '@visactor/v import type { IBounds, IPointLike, Maybe } from '@visactor/vutils'; // eslint-disable-next-line no-duplicate-imports import { array, polygonIntersectPolygon, isValid, last } from '@visactor/vutils'; -import type { IModelRenderOption, IModelSpecInfo } from '../../model/interface'; +import type { IModelSpecInfo } from '../../model/interface'; import type { IRegion } from '../../region/interface'; import type { IGraphic, IGroup, INode, IPolygon } from '@visactor/vrender-core'; import { transformToGraphic } from '../../util/style'; @@ -24,6 +24,7 @@ import { getSpecInfo } from '../util'; import { brush } from '../../theme/builtin/common/component/brush'; import { isReverse, statePointToData } from '../data-zoom/util'; import type { CartesianAxis } from '../axis/cartesian'; +import type { IRenderOption } from '../../compile/interface'; const IN_BRUSH_STATE = 'inBrush'; const OUT_BRUSH_STATE = 'outOfBrush'; @@ -47,6 +48,8 @@ export class Brush extends BaseComponent i protected _relativeRegions!: IRegion[]; protected _linkedSeries: ISeries[] = []; + protected _operateMask: IPolygon; + private _itemMap: { [regionId: string | number]: IMark[] } = {}; private _linkedItemMap: { [seriesId: string | number]: IMark[] } = {}; @@ -249,6 +252,10 @@ export class Brush extends BaseComponent i brushComponent.children[0].removeAllChild(); } + protected _shouldEnableInteractive() { + return (this.getOption().getCompiler().getOption() as IRenderOption).interactive !== false; + } + protected _createBrushComponent(region: IRegion, componentIndex: number) { const interactiveAttr = this._getBrushInteractiveAttr(region); const brush = new BrushComponent({ @@ -257,7 +264,6 @@ export class Brush extends BaseComponent i ...interactiveAttr, ...this._spec, disableTriggerEvent: this._option.disableTriggerEvent - // beforeBrushChange: this._spec.beforeBrushChange }); brush.id = this._spec.id ?? `brush-${this.id}`; this.getContainer().add(brush as unknown as INode); @@ -347,7 +353,8 @@ export class Brush extends BaseComponent i maxX: seriesRegionEndX }, xRange: [seriesRegionStartX, seriesRegionEndX], - yRange: [seriesRegionStartY, seriesRegionEndY] + yRange: [seriesRegionStartY, seriesRegionEndY], + interactive: this._shouldEnableInteractive() } as BrushInteractiveRangeAttr; } @@ -375,6 +382,7 @@ export class Brush extends BaseComponent i /*** start: event dispatch ***/ private _handleBrushChange(region: IRegion, e: any) { const { operateMask } = e.detail as any; + this._operateMask = operateMask; const { updateElementsState = true } = this._spec; if (updateElementsState) { this._reconfigItem(operateMask, region); From 373083dd2f8628dc6e3fa28e78eea5fa71328c41 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 5 Jan 2026 17:45:24 +0800 Subject: [PATCH 3/9] chore: lint error --- packages/vchart/src/compile/interface/compilable-item.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vchart/src/compile/interface/compilable-item.ts b/packages/vchart/src/compile/interface/compilable-item.ts index 3d57ee2684..272b7a521c 100644 --- a/packages/vchart/src/compile/interface/compilable-item.ts +++ b/packages/vchart/src/compile/interface/compilable-item.ts @@ -34,6 +34,7 @@ export interface IGrammarItemMap { export type ICompilerModel = Record>; export interface ICompiler { + getOption: () => IVChartRenderOption; isInited?: boolean; readonly stateAnimationConfig?: MarkAnimationSpec; getCanvas: () => HTMLCanvasElement | undefined; From 6acb4698743c64402889fa7337a4a629bd4dc919 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 5 Jan 2026 20:16:15 +0800 Subject: [PATCH 4/9] fix: build error --- packages/vchart/src/compile/interface/compilable-item.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vchart/src/compile/interface/compilable-item.ts b/packages/vchart/src/compile/interface/compilable-item.ts index 272b7a521c..acc94d112e 100644 --- a/packages/vchart/src/compile/interface/compilable-item.ts +++ b/packages/vchart/src/compile/interface/compilable-item.ts @@ -6,7 +6,7 @@ import type { IMorphConfig } from '../../animation/spec'; import type { IBoundsLike } from '@visactor/vutils'; import type { EventSourceType, EventType } from '../../event/interface'; import type { IMark, IMarkGraphic } from '../../mark/interface'; -import type { LayoutState } from '../interface/compiler'; +import type { IRenderOption, LayoutState } from '../interface/compiler'; import type { MarkAnimationSpec } from '../../animation/interface'; export type CompilerListenerParameters = { @@ -34,7 +34,7 @@ export interface IGrammarItemMap { export type ICompilerModel = Record>; export interface ICompiler { - getOption: () => IVChartRenderOption; + getOption: () => IRenderOption; isInited?: boolean; readonly stateAnimationConfig?: MarkAnimationSpec; getCanvas: () => HTMLCanvasElement | undefined; From 2ecca9ddc8d9dcdaabe468918ebabd3c353037ef Mon Sep 17 00:00:00 2001 From: skie1997 Date: Wed, 7 Jan 2026 11:55:25 +0800 Subject: [PATCH 5/9] feat: add brush clear api and disable dimension hover config. close #4400 --- .../feat-brush-api_2026-01-07-03-54.json | 10 ++++ packages/vchart/src/component/brush/brush.ts | 49 +++++++++++++++++++ .../vchart/src/component/brush/interface.ts | 5 ++ .../src/component/crosshair/interface/spec.ts | 1 + packages/vchart/src/core/interface.ts | 13 ++++- packages/vchart/src/core/vchart.ts | 14 ++---- packages/vchart/src/event/event.ts | 2 +- .../event/events/dimension/dimension-hover.ts | 9 +++- 8 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 common/changes/@visactor/vchart/feat-brush-api_2026-01-07-03-54.json diff --git a/common/changes/@visactor/vchart/feat-brush-api_2026-01-07-03-54.json b/common/changes/@visactor/vchart/feat-brush-api_2026-01-07-03-54.json new file mode 100644 index 0000000000..fbef58a0fd --- /dev/null +++ b/common/changes/@visactor/vchart/feat-brush-api_2026-01-07-03-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: add brush clear api and disable dimension hover config. close#4400", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/component/brush/brush.ts b/packages/vchart/src/component/brush/brush.ts index 9a18421698..d8dac36fcc 100644 --- a/packages/vchart/src/component/brush/brush.ts +++ b/packages/vchart/src/component/brush/brush.ts @@ -25,6 +25,8 @@ import { brush } from '../../theme/builtin/common/component/brush'; import { isReverse, statePointToData } from '../data-zoom/util'; import type { CartesianAxis } from '../axis/cartesian'; import type { IRenderOption } from '../../compile/interface'; +import { DimensionHoverEvent } from '../../event'; +import type { ICrossHair } from '../crosshair'; const IN_BRUSH_STATE = 'inBrush'; const OUT_BRUSH_STATE = 'outOfBrush'; @@ -276,11 +278,17 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.drawStart, (e: any) => { + if (this._spec.disableDimensionHoverWhenBrushing) { + this.disableDimensionHover(); + } this._setRegionMarkPickable(region, true); this._emitEvent(ChartEvent.brushStart, region, e); }); brush.addEventListener(BrushEvent.moveStart, (e: any) => { + if (this._spec.disableDimensionHoverWhenBrushing) { + this.disableDimensionHover(); + } this._setRegionMarkPickable(region, true); this._emitEvent(ChartEvent.brushStart, region, e); }); @@ -298,12 +306,16 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.brushClear, (e: any) => { + if (this._spec.disableDimensionHoverWhenBrushing) { + this.enableDimensionHover(); + } this._setRegionMarkPickable(region, true); this._initMarkBrushState(componentIndex, ''); this._emitEvent(ChartEvent.brushClear, region, e); }); brush.addEventListener(BrushEvent.drawEnd, (e: any) => { + this.enableDimensionHover(); this._setRegionMarkPickable(region, true); const { operateMask } = e.detail as any; const { updateElementsState = true } = this._spec; @@ -327,6 +339,7 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.moveEnd, (e: any) => { + this.enableDimensionHover(); this._setRegionMarkPickable(region, true); const { operateMask } = e.detail as any; const { updateElementsState = true } = this._spec; @@ -777,6 +790,42 @@ export class Brush extends BaseComponent i this._brushComponents = null; } } + + disableDimensionHover() { + // dimension hover event + DimensionHoverEvent.disableDimensionEvent(true); + + // crosshair + this._option + .getChart() + .getComponentsByKey('crosshair') + .forEach(crosshair => ((crosshair as ICrossHair).enable = false)); + + // tooltip + // eslint-disable-next-line @typescript-eslint/no-empty-function + this._option.globalInstance.setTooltipHandler((() => {}) as any); + } + + enableDimensionHover() { + // dimension hover event + DimensionHoverEvent.disableDimensionEvent(false); + + // crosshair + this._option + .getChart() + .getComponentsByKey('crosshair') + .forEach(crosshair => ((crosshair as ICrossHair).enable = true)); + + // tooltip + this._option.globalInstance.setTooltipHandler(undefined); + } + + clearBrushStateAndMask() { + this._relativeRegions.forEach((region: IRegion, componentIndex: number) => { + this._initMarkBrushState(componentIndex, ''); + this._brushComponents[componentIndex].children[0].removeAllChild(); + }); + } } export const registerBrush = () => { diff --git a/packages/vchart/src/component/brush/interface.ts b/packages/vchart/src/component/brush/interface.ts index 5ff1e12510..5e3b1475d3 100644 --- a/packages/vchart/src/component/brush/interface.ts +++ b/packages/vchart/src/component/brush/interface.ts @@ -70,6 +70,11 @@ interface IBrushDataBindSpec { * 返回false, 则阻止后续逻辑 */ beforeBrushChange?: (e: FederatedPointerEvent) => void | boolean; + /** + * 是否在框选时禁用维度 hover 事件 + * @default false + */ + disableDimensionHoverWhenBrushing?: boolean; } export interface IBrushTheme { diff --git a/packages/vchart/src/component/crosshair/interface/spec.ts b/packages/vchart/src/component/crosshair/interface/spec.ts index 0e64821eb8..49ccc0291a 100644 --- a/packages/vchart/src/component/crosshair/interface/spec.ts +++ b/packages/vchart/src/component/crosshair/interface/spec.ts @@ -5,6 +5,7 @@ import type { IComponentSpec } from '../../base/interface'; import type { IComponent } from '../../interface'; export interface ICrossHair extends IComponent { + enable: boolean; clearAxisValue: () => void; setAxisValue: (v: StringOrNumber, axis: IAxis) => void; layoutByValue: (enableRemain?: boolean) => void; diff --git a/packages/vchart/src/core/interface.ts b/packages/vchart/src/core/interface.ts index 1e8b35a9d1..c0d92f3828 100644 --- a/packages/vchart/src/core/interface.ts +++ b/packages/vchart/src/core/interface.ts @@ -15,7 +15,7 @@ import type { } from '../typings'; import type { IMorphConfig } from '../animation/spec'; import type { IBoundsLike } from '@visactor/vutils'; -import type { EventCallback, EventQuery, EventType, ExtendEventParam } from '../event/interface'; +import type { EventCallback, EventParamsDefinition, EventQuery, EventType, ExtendEventParam } from '../event/interface'; import type { IMark, IMarkDataTransform } from '../mark/interface'; import type { ISeries } from '../series/interface/series'; import type { ITheme } from '../theme/interface'; @@ -592,7 +592,10 @@ export interface VRenderComponentOptions { } export interface IStageEventPlugin { - new (taget: IEventTarget, cfg?: T): { + new ( + taget: IEventTarget, + cfg?: T + ): { release: () => void; }; } @@ -603,3 +606,9 @@ export interface GrammarTransformOption { transform: IMarkDataTransform; runType?: 'beforeJoin' | 'afterEncode'; } + +export interface UserEvent { + eType: EventType; + query: EventQuery | EventCallback; + handler?: EventCallback; +} diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index 13d475aba7..2324f38bbf 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -19,7 +19,6 @@ import type { IComponentConstructor } from '../component/interface'; import { ComponentTypeEnum } from '../component/interface/type'; import type { EventCallback, - EventParamsDefinition, EventQuery, EventType, ExtendEventParam, @@ -93,6 +92,7 @@ import type { IGlobalConfig, IVChart, IVChartRenderOption, + UserEvent, VChartRenderActionSource } from './interface'; import { InstanceManager } from './instance-manager'; @@ -324,11 +324,7 @@ export class VChart implements IVChart { get event() { return this._event; } - private _userEvents: { - eType: EventType; - query: EventQuery | EventCallback; - handler?: EventCallback; - }[] = []; + private _userEvents: UserEvent[] = []; private _eventDispatcher: Maybe; private _dataSet!: Maybe; getDataSet() { @@ -454,7 +450,7 @@ export class VChart implements IVChart { // 设置全局字体 this._setFontFamilyTheme(this.getTheme('fontFamily') as string); this._initDataSet(this._option.dataSet); - this._autoSize = isTrueBrowseEnv ? spec.autoFit ?? this._option.autoFit ?? true : false; + this._autoSize = isTrueBrowseEnv ? (spec.autoFit ?? this._option.autoFit ?? true) : false; this._bindResizeEvent(); this._bindViewEvent(); this._initChartPlugin(); @@ -1521,7 +1517,7 @@ export class VChart implements IVChart { } const lasAutoSize = this._autoSize; - this._autoSize = isTrueBrowser(this._option.mode) ? this._spec.autoFit ?? this._option.autoFit ?? true : false; + this._autoSize = isTrueBrowser(this._option.mode) ? (this._spec.autoFit ?? this._option.autoFit ?? true) : false; if (this._autoSize !== lasAutoSize) { resize = true; } @@ -2259,7 +2255,7 @@ export class VChart implements IVChart { }; } - public runDisappearAnimation() { + runDisappearAnimation() { this._renderState = RenderStateEnum.disappear; this.getStage().eventSystem.pauseTriggerEvent(); this.getStage().applyAnimationState( diff --git a/packages/vchart/src/event/event.ts b/packages/vchart/src/event/event.ts index ca9cff5d49..2a875bc425 100644 --- a/packages/vchart/src/event/event.ts +++ b/packages/vchart/src/event/event.ts @@ -49,7 +49,7 @@ export class Event implements IEvent { if (ComposedEventCtor) { const composedEvent = new ComposedEventCtor(this._eventDispatcher, this._mode) as IComposedEvent; composedEvent.register(eType, handler); - this._composedEventMap.set(callback as EventCallback, { + this._composedEventMap.set(handler.callback as EventCallback, { eventType: eType, event: composedEvent }); diff --git a/packages/vchart/src/event/events/dimension/dimension-hover.ts b/packages/vchart/src/event/events/dimension/dimension-hover.ts index f66926e29d..29deaf05bb 100644 --- a/packages/vchart/src/event/events/dimension/dimension-hover.ts +++ b/packages/vchart/src/event/events/dimension/dimension-hover.ts @@ -6,6 +6,11 @@ import { Event_Source_Type } from '../../../constant/event'; import type { IDimensionInfo } from './interface'; export class DimensionHoverEvent extends DimensionEvent { + static _disableDimensionEvent: boolean = false; + static disableDimensionEvent(value: boolean) { + this._disableDimensionEvent = value; + } + private _cacheDimensionInfo: IDimensionInfo[] | null = null; register(eType: Evt, handler: EventHandler) { @@ -46,7 +51,7 @@ export class DimensionHoverEvent extends DimensionEvent { } private onMouseMove = (params: BaseEventParams) => { - if (!params) { + if (!params || DimensionHoverEvent._disableDimensionEvent) { return; } const x = (params.event as any).viewX; @@ -84,7 +89,7 @@ export class DimensionHoverEvent extends DimensionEvent { }; private onMouseOut = (params: BaseEventParams) => { - if (!params) { + if (!params || DimensionHoverEvent._disableDimensionEvent) { return; } // 鼠标移出某维度 From 95fbb385d389b0d9c40c52619bfa8842898ddf86 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Wed, 7 Jan 2026 21:06:44 +0800 Subject: [PATCH 6/9] feat: add disable dimension and crosshair and tooltip api --- packages/vchart/src/component/brush/brush.ts | 46 ++++--------------- .../src/component/tooltip/interface/common.ts | 1 + .../src/component/tooltip/processor/base.ts | 3 ++ .../vchart/src/component/tooltip/tooltip.ts | 3 +- packages/vchart/src/core/interface.ts | 15 ++++++ packages/vchart/src/core/vchart.ts | 18 +++++++- 6 files changed, 47 insertions(+), 39 deletions(-) diff --git a/packages/vchart/src/component/brush/brush.ts b/packages/vchart/src/component/brush/brush.ts index d8dac36fcc..22b43a4ccb 100644 --- a/packages/vchart/src/component/brush/brush.ts +++ b/packages/vchart/src/component/brush/brush.ts @@ -25,8 +25,6 @@ import { brush } from '../../theme/builtin/common/component/brush'; import { isReverse, statePointToData } from '../data-zoom/util'; import type { CartesianAxis } from '../axis/cartesian'; import type { IRenderOption } from '../../compile/interface'; -import { DimensionHoverEvent } from '../../event'; -import type { ICrossHair } from '../crosshair'; const IN_BRUSH_STATE = 'inBrush'; const OUT_BRUSH_STATE = 'outOfBrush'; @@ -279,7 +277,7 @@ export class Brush extends BaseComponent i brush.addEventListener(BrushEvent.drawStart, (e: any) => { if (this._spec.disableDimensionHoverWhenBrushing) { - this.disableDimensionHover(); + this._option.globalInstance.disableDimensionHoverEvent(true); } this._setRegionMarkPickable(region, true); this._emitEvent(ChartEvent.brushStart, region, e); @@ -287,7 +285,7 @@ export class Brush extends BaseComponent i brush.addEventListener(BrushEvent.moveStart, (e: any) => { if (this._spec.disableDimensionHoverWhenBrushing) { - this.disableDimensionHover(); + this._option.globalInstance.disableDimensionHoverEvent(true); } this._setRegionMarkPickable(region, true); this._emitEvent(ChartEvent.brushStart, region, e); @@ -307,7 +305,7 @@ export class Brush extends BaseComponent i brush.addEventListener(BrushEvent.brushClear, (e: any) => { if (this._spec.disableDimensionHoverWhenBrushing) { - this.enableDimensionHover(); + this._option.globalInstance.disableDimensionHoverEvent(false); } this._setRegionMarkPickable(region, true); this._initMarkBrushState(componentIndex, ''); @@ -315,7 +313,9 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.drawEnd, (e: any) => { - this.enableDimensionHover(); + if (this._spec.disableDimensionHoverWhenBrushing) { + this._option.globalInstance.disableDimensionHoverEvent(false); + } this._setRegionMarkPickable(region, true); const { operateMask } = e.detail as any; const { updateElementsState = true } = this._spec; @@ -339,7 +339,9 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.moveEnd, (e: any) => { - this.enableDimensionHover(); + if (this._spec.disableDimensionHoverWhenBrushing) { + this._option.globalInstance.disableDimensionHoverEvent(false); + } this._setRegionMarkPickable(region, true); const { operateMask } = e.detail as any; const { updateElementsState = true } = this._spec; @@ -790,36 +792,6 @@ export class Brush extends BaseComponent i this._brushComponents = null; } } - - disableDimensionHover() { - // dimension hover event - DimensionHoverEvent.disableDimensionEvent(true); - - // crosshair - this._option - .getChart() - .getComponentsByKey('crosshair') - .forEach(crosshair => ((crosshair as ICrossHair).enable = false)); - - // tooltip - // eslint-disable-next-line @typescript-eslint/no-empty-function - this._option.globalInstance.setTooltipHandler((() => {}) as any); - } - - enableDimensionHover() { - // dimension hover event - DimensionHoverEvent.disableDimensionEvent(false); - - // crosshair - this._option - .getChart() - .getComponentsByKey('crosshair') - .forEach(crosshair => ((crosshair as ICrossHair).enable = true)); - - // tooltip - this._option.globalInstance.setTooltipHandler(undefined); - } - clearBrushStateAndMask() { this._relativeRegions.forEach((region: IRegion, componentIndex: number) => { this._initMarkBrushState(componentIndex, ''); diff --git a/packages/vchart/src/component/tooltip/interface/common.ts b/packages/vchart/src/component/tooltip/interface/common.ts index c7509fdd87..6b4fb96fdf 100644 --- a/packages/vchart/src/component/tooltip/interface/common.ts +++ b/packages/vchart/src/component/tooltip/interface/common.ts @@ -49,4 +49,5 @@ export interface ITooltip extends IComponent { tooltipHandler?: ITooltipHandler; getVisible: () => boolean; showTooltip: (datum: Datum, options: IShowTooltipOption) => void; + enable?: boolean; } diff --git a/packages/vchart/src/component/tooltip/processor/base.ts b/packages/vchart/src/component/tooltip/processor/base.ts index f473dac2c0..4636aa90bb 100644 --- a/packages/vchart/src/component/tooltip/processor/base.ts +++ b/packages/vchart/src/component/tooltip/processor/base.ts @@ -151,6 +151,9 @@ export abstract class BaseTooltipProcessor { /** 判断是否应该触发 tooltip */ shouldHandleTooltip(params: BaseEventParams, info: TooltipInfo): boolean { + if (!this.component.enable) { + return false; + } if (isNil(info)) { return false; } diff --git a/packages/vchart/src/component/tooltip/tooltip.ts b/packages/vchart/src/component/tooltip/tooltip.ts index c781069792..30fe4ecca1 100644 --- a/packages/vchart/src/component/tooltip/tooltip.ts +++ b/packages/vchart/src/component/tooltip/tooltip.ts @@ -68,9 +68,10 @@ export class Tooltip extends BaseComponent implements ITooltip { * 是否正在浏览tooltip内容 */ private _isEnterTooltip: boolean; - protected declare _spec: ITooltipSpec; + declare protected _spec: ITooltipSpec; tooltipHandler?: ITooltipHandler; + enable?: boolean = true; processor: ITooltipActiveTypeAsKeys< ITooltipProcessor, diff --git a/packages/vchart/src/core/interface.ts b/packages/vchart/src/core/interface.ts index c0d92f3828..e33e30794a 100644 --- a/packages/vchart/src/core/interface.ts +++ b/packages/vchart/src/core/interface.ts @@ -451,6 +451,21 @@ export interface IVChart { */ setDimensionIndex: (value: StringOrNumber, options?: DimensionIndexOption) => void; + /** + * 禁用/开启 dimension 交互事件 + */ + disableDimensionHoverEvent: (disabled: boolean) => void; + + /** + * 禁用/开启 crosshair + */ + disableCrossHair: (disabled: boolean) => void; + + /** + * 禁用/开启 tooltip + */ + disableTooltip: (disabled: boolean) => void; + // 数据转换相关的 api /** * Convert the data to coordinate position diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index 2324f38bbf..660fd77577 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -51,7 +51,7 @@ import { registerDataSetInstanceParser, registerDataSetInstanceTransform } from import { dataToDataView } from '../data/initialize'; import { copyDataView } from '../data/transforms/copy-data-view'; import type { ITooltipHandler } from '../typings/tooltip'; -import type { Tooltip } from '../component/tooltip'; +import type { ITooltip, Tooltip } from '../component/tooltip'; import type { Datum, IPoint, @@ -118,6 +118,8 @@ import { registerElementSelect } from '../interaction/triggers/element-select'; import type { IVChartPluginService } from '../plugin/vchart/interface'; import { VChartPluginService } from '../plugin/vchart/plugin-service'; import { RenderStateEnum } from '../constant/animate'; +import { DimensionHoverEvent } from '../event'; +import type { ICrossHair } from '../component/crosshair'; export class VChart implements IVChart { readonly id = createID(); @@ -1911,6 +1913,20 @@ export class VChart implements IVChart { return this._chart?.setDimensionIndex(value, opt); } + disableDimensionHoverEvent(value: boolean = true) { + DimensionHoverEvent.disableDimensionEvent(value); + } + disableCrossHair(value: boolean = true) { + this.getChart() + .getComponentsByKey('crosshair') + .forEach(crosshair => ((crosshair as ICrossHair).enable = !value)); + } + disableTooltip(value: boolean = true) { + this.getChart() + .getComponentsByKey('tooltip') + .forEach(tooltip => ((tooltip as ITooltip).enable = !value)); + } + showCrosshair(cb: (axis: IAxis) => false | string | number) { this._chart?.showCrosshair(cb); } From b8a8ff467a4b830d3347839465bb318cee2add55 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Thu, 8 Jan 2026 20:31:57 +0800 Subject: [PATCH 7/9] fix: add dimension hover api to instance --- packages/vchart/src/core/interface.ts | 5 +++-- packages/vchart/src/core/vchart.ts | 10 +++++++--- .../src/event/events/dimension/dimension-hover.ts | 7 +------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/vchart/src/core/interface.ts b/packages/vchart/src/core/interface.ts index e33e30794a..018b8480f9 100644 --- a/packages/vchart/src/core/interface.ts +++ b/packages/vchart/src/core/interface.ts @@ -452,9 +452,10 @@ export interface IVChart { setDimensionIndex: (value: StringOrNumber, options?: DimensionIndexOption) => void; /** - * 禁用/开启 dimension 交互事件 + * 如果传入参数, 则禁用/开启 dimension 交互事件 + * 如果不传入参数, 获取当前是否禁用 dimension 交互事件 */ - disableDimensionHoverEvent: (disabled: boolean) => void; + disableDimensionHoverEvent: (disabled?: boolean) => void; /** * 禁用/开启 crosshair diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index 660fd77577..b3081dd4af 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -118,7 +118,6 @@ import { registerElementSelect } from '../interaction/triggers/element-select'; import type { IVChartPluginService } from '../plugin/vchart/interface'; import { VChartPluginService } from '../plugin/vchart/plugin-service'; import { RenderStateEnum } from '../constant/animate'; -import { DimensionHoverEvent } from '../event'; import type { ICrossHair } from '../component/crosshair'; export class VChart implements IVChart { @@ -367,6 +366,8 @@ export class VChart implements IVChart { private _renderState: RenderStateEnum = RenderStateEnum.render; + protected _disableDimensionHoverEvent: boolean = false; + constructor(spec: ISpec, options: IInitOption) { removeUndefined(options); this._option = { @@ -1913,8 +1914,11 @@ export class VChart implements IVChart { return this._chart?.setDimensionIndex(value, opt); } - disableDimensionHoverEvent(value: boolean = true) { - DimensionHoverEvent.disableDimensionEvent(value); + disableDimensionHoverEvent(value?: boolean) { + if (value !== undefined) { + this._disableDimensionHoverEvent = value; + } + return this._disableDimensionHoverEvent; } disableCrossHair(value: boolean = true) { this.getChart() diff --git a/packages/vchart/src/event/events/dimension/dimension-hover.ts b/packages/vchart/src/event/events/dimension/dimension-hover.ts index 29deaf05bb..146acdf781 100644 --- a/packages/vchart/src/event/events/dimension/dimension-hover.ts +++ b/packages/vchart/src/event/events/dimension/dimension-hover.ts @@ -6,11 +6,6 @@ import { Event_Source_Type } from '../../../constant/event'; import type { IDimensionInfo } from './interface'; export class DimensionHoverEvent extends DimensionEvent { - static _disableDimensionEvent: boolean = false; - static disableDimensionEvent(value: boolean) { - this._disableDimensionEvent = value; - } - private _cacheDimensionInfo: IDimensionInfo[] | null = null; register(eType: Evt, handler: EventHandler) { @@ -51,7 +46,7 @@ export class DimensionHoverEvent extends DimensionEvent { } private onMouseMove = (params: BaseEventParams) => { - if (!params || DimensionHoverEvent._disableDimensionEvent) { + if (!params || params.chart?.getOption()?.globalInstance?.disableDimensionHoverEvent?.()) { return; } const x = (params.event as any).viewX; From ca6d63929a128d966b72afee25fd146c0f714672 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Thu, 8 Jan 2026 20:33:05 +0800 Subject: [PATCH 8/9] fix: add dimension hover api to instance --- packages/vchart/src/event/events/dimension/dimension-hover.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vchart/src/event/events/dimension/dimension-hover.ts b/packages/vchart/src/event/events/dimension/dimension-hover.ts index 146acdf781..2e53086039 100644 --- a/packages/vchart/src/event/events/dimension/dimension-hover.ts +++ b/packages/vchart/src/event/events/dimension/dimension-hover.ts @@ -84,7 +84,7 @@ export class DimensionHoverEvent extends DimensionEvent { }; private onMouseOut = (params: BaseEventParams) => { - if (!params || DimensionHoverEvent._disableDimensionEvent) { + if (!params || params.chart?.getOption()?.globalInstance?.disableDimensionHoverEvent?.()) { return; } // 鼠标移出某维度 From b5921c97807840a24ab9473279457b27e00684e6 Mon Sep 17 00:00:00 2001 From: skie1997 Date: Mon, 19 Jan 2026 15:30:29 +0800 Subject: [PATCH 9/9] feat: interactive params add event. feat #4421 --- ...lease-2.0.13-alpha.9_2026-01-19-07-28.json | 10 ++++++++ .../src/interaction/interface/trigger.ts | 2 +- .../vchart/src/interaction/triggers/base.ts | 5 ++-- .../interaction/triggers/element-highlight.ts | 20 ++++++++-------- .../interaction/triggers/element-select.ts | 24 +++++++++---------- 5 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 common/changes/@visactor/vchart/pre-release-2.0.13-alpha.9_2026-01-19-07-28.json diff --git a/common/changes/@visactor/vchart/pre-release-2.0.13-alpha.9_2026-01-19-07-28.json b/common/changes/@visactor/vchart/pre-release-2.0.13-alpha.9_2026-01-19-07-28.json new file mode 100644 index 0000000000..c1736bcb15 --- /dev/null +++ b/common/changes/@visactor/vchart/pre-release-2.0.13-alpha.9_2026-01-19-07-28.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: interactive params add event. feat #4421", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/interaction/interface/trigger.ts b/packages/vchart/src/interaction/interface/trigger.ts index 3228be8b4b..b24e915426 100644 --- a/packages/vchart/src/interaction/interface/trigger.ts +++ b/packages/vchart/src/interaction/interface/trigger.ts @@ -13,7 +13,7 @@ export interface ITrigger { release: () => void; init: () => void; - start: (g: any) => void; + start: (g: any, e?: BaseEventParams) => void; reset: (g?: IMarkGraphic) => void; getStartState: () => string; getResetState: () => string; diff --git a/packages/vchart/src/interaction/triggers/base.ts b/packages/vchart/src/interaction/triggers/base.ts index e3ba92a4ac..a80c390809 100644 --- a/packages/vchart/src/interaction/triggers/base.ts +++ b/packages/vchart/src/interaction/triggers/base.ts @@ -3,6 +3,7 @@ import type { IBaseTriggerOptions, ITrigger, ITriggerEventHandler } from '../int import type { IMark, IMarkGraphic } from '../../mark/interface/common'; import { MarkSet } from '../../mark/mark-set'; import { groupMarksByState } from './util'; +import type { BaseEventParams } from '../../core'; export abstract class BaseTrigger implements ITrigger { options: T; @@ -111,11 +112,11 @@ export abstract class BaseTrigger implements ITri } } - start(g: IMarkGraphic | string) { + start(g: IMarkGraphic | string, e?: BaseEventParams) { // do nothing } - reset(g?: IMarkGraphic) { + reset(g?: IMarkGraphic, e?: BaseEventParams) { // do nothing } diff --git a/packages/vchart/src/interaction/triggers/element-highlight.ts b/packages/vchart/src/interaction/triggers/element-highlight.ts index d9b1d58625..6a3bcddc80 100644 --- a/packages/vchart/src/interaction/triggers/element-highlight.ts +++ b/packages/vchart/src/interaction/triggers/element-highlight.ts @@ -65,13 +65,13 @@ export class ElementHighlight return events; } - resetAll = () => { + resetAll = (e?: BaseEventParams) => { const { highlightState, blurState, interaction } = this.options; if (this._lastGraphic) { interaction.clearAllStatesOfTrigger(this, highlightState, blurState); - this.dispatchEvent('reset', { graphics: [this._lastGraphic], options: this.options }); + this.dispatchEvent('reset', { graphics: [this._lastGraphic], options: this.options, ...e }); this._lastGraphic = null; @@ -80,7 +80,7 @@ export class ElementHighlight }; handleStart = (e: BaseEventParams) => { - this.start(e.item); + this.start(e.item, e); }; handleReset = (e: BaseEventParams) => { @@ -94,13 +94,13 @@ export class ElementHighlight const hasActiveElement = markGraphic && this._markSet.getMarkInId(markGraphic.context.markId); if (this._resetType.includes('view') && !hasActiveElement) { - this.resetAll(); + this.resetAll(e); } else if (this._resetType.includes('self') && hasActiveElement) { - this.resetAll(); + this.resetAll(e); } }; - start(markGraphic: IMarkGraphic) { + start(markGraphic: IMarkGraphic, e?: BaseEventParams) { if (markGraphic && this._markSet.getMarkInId(markGraphic.context.markId)) { const { highlightState, blurState, interaction } = this.options; @@ -119,19 +119,19 @@ export class ElementHighlight this._lastGraphic = markGraphic; - this.dispatchEvent('start', { graphics: newStatedGraphics, options: this.options }); + this.dispatchEvent('start', { graphics: newStatedGraphics, options: this.options, ...e }); } else if (this._lastGraphic && this._resetType === 'view') { - this.resetAll(); + this.resetAll(e); } } - reset(markGraphic: IMarkGraphic) { + reset(markGraphic: IMarkGraphic, e?: BaseEventParams) { if (markGraphic) { if (this._markSet.getMarkInId(markGraphic.context.markId)) { markGraphic.removeState([this.options.highlightState, this.options.blurState]); } } else { - this.resetAll(); + this.resetAll(e); } } } diff --git a/packages/vchart/src/interaction/triggers/element-select.ts b/packages/vchart/src/interaction/triggers/element-select.ts index 9b63b005db..b13b3acfe1 100644 --- a/packages/vchart/src/interaction/triggers/element-select.ts +++ b/packages/vchart/src/interaction/triggers/element-select.ts @@ -61,21 +61,21 @@ export class ElementSelect extends BaseTrigger implements return events; } - resetAll = () => { + resetAll = (e?: BaseEventParams) => { const { state, reverseState, interaction } = this.options; const statedGraphics = interaction.getStatedGraphics(this); if (statedGraphics && statedGraphics.length) { interaction.clearAllStatesOfTrigger(this, state, reverseState); - this.dispatchEvent('reset', { graphics: statedGraphics, options: this.options }); + this.dispatchEvent('reset', { graphics: statedGraphics, options: this.options, ...e }); interaction.setStatedGraphics(this, []); } }; handleStart = (e: BaseEventParams) => { - this.start(e.item); + this.start(e.item, e); }; handleReset = (e: BaseEventParams) => { @@ -89,13 +89,13 @@ export class ElementSelect extends BaseTrigger implements const hasActiveElement = markGraphic && this._markSet.getMarkInId(markGraphic.context.markId); if (this._resetType.includes('view') && !hasActiveElement) { - this.resetAll(); + this.resetAll(e); } else if (this._resetType.includes('self') && hasActiveElement) { - this.resetAll(); + this.resetAll(e); } }; - start(markGraphic: IMarkGraphic) { + start(markGraphic: IMarkGraphic, e?: BaseEventParams) { const { state, reverseState, isMultiple, interaction } = this.options; const statedGraphics = interaction.getStatedGraphics(this); @@ -110,7 +110,7 @@ export class ElementSelect extends BaseTrigger implements interaction.updateStates(this, newStatedGraphics, statedGraphics, state, reverseState) ); } else { - this.resetAll(); + this.resetAll(e); } } } else { @@ -127,26 +127,26 @@ export class ElementSelect extends BaseTrigger implements reverseState ); interaction.setStatedGraphics(this, newStatedGraphics); - this.dispatchEvent('start', { graphics: newStatedGraphics, options: this.options }); + this.dispatchEvent('start', { graphics: newStatedGraphics, options: this.options, ...e }); if (this._resetType.includes('timeout')) { this._timer = setTimeout(() => { - this.resetAll(); + this.resetAll(e); }, this.options.triggerOff as number) as unknown as number; } } } else if (this._resetType.includes('view') && statedGraphics && statedGraphics.length) { - this.resetAll(); + this.resetAll(e); } } - reset(markGraphic: IMarkGraphic) { + reset(markGraphic: IMarkGraphic, e?: BaseEventParams) { if (markGraphic) { if (this._markSet.getMarkInId(markGraphic.context.markId)) { markGraphic.removeState([this.options.state, this.options.reverseState]); } } else { - this.resetAll(); + this.resetAll(e); } } }