From 6bdfff4ba4fbfa18a4f33b92149707b3c7fd3edf Mon Sep 17 00:00:00 2001 From: xile611 Date: Wed, 5 Feb 2025 19:53:26 +0800 Subject: [PATCH 1/3] refactor: optimize the process of theme --- .../src/chart/base/base-chart-transformer.ts | 2 +- packages/vchart/src/chart/base/base-chart.ts | 6 +- packages/vchart/src/component/axis/util.ts | 27 ++++---- .../base/base-component-transformer.ts | 2 +- packages/vchart/src/component/base/util.ts | 26 ++++---- .../src/component/crosshair/utils/common.ts | 9 ++- packages/vchart/src/component/util.ts | 7 +-- packages/vchart/src/core/vchart.ts | 61 +++++++++++++++---- packages/vchart/src/model/base-model.ts | 2 +- packages/vchart/src/model/interface.ts | 2 +- .../tooltip-handler/canvas-tooltip-handler.ts | 4 +- .../tooltip-handler/dom-tooltip-handler.ts | 4 +- .../tooltip-handler/utils/attribute.ts | 12 ++-- .../series/base/base-series-transformer.ts | 12 ++-- packages/vchart/src/series/word-cloud/base.ts | 4 +- packages/vchart/src/theme/builtin/index.ts | 15 ++--- .../vchart/src/theme/color-scheme/util.ts | 4 +- packages/vchart/src/theme/theme-manager.ts | 2 +- packages/vchart/src/util/theme/common.ts | 4 +- packages/vchart/src/util/theme/merge-theme.ts | 5 +- packages/vchart/src/util/theme/preprocess.ts | 18 ++---- 21 files changed, 125 insertions(+), 103 deletions(-) diff --git a/packages/vchart/src/chart/base/base-chart-transformer.ts b/packages/vchart/src/chart/base/base-chart-transformer.ts index 59aec151c7..dca84cb002 100644 --- a/packages/vchart/src/chart/base/base-chart-transformer.ts +++ b/packages/vchart/src/chart/base/base-chart-transformer.ts @@ -172,7 +172,7 @@ export class BaseChartSpecTransformer implements IChartSpe seriesStyle: chartSpec.seriesStyle, animation: chartSpec.animation ?? this._option.animation, - animationThreshold: chartSpec.animationThreshold ?? this._option.getTheme?.().animationThreshold, + animationThreshold: chartSpec.animationThreshold ?? this._option.getTheme?.('animationThreshold'), animationAppear: chartSpec.animationAppear, animationDisappear: chartSpec.animationDisappear, animationEnter: chartSpec.animationEnter, diff --git a/packages/vchart/src/chart/base/base-chart.ts b/packages/vchart/src/chart/base/base-chart.ts index a96c91f953..96e29b3380 100644 --- a/packages/vchart/src/chart/base/base-chart.ts +++ b/packages/vchart/src/chart/base/base-chart.ts @@ -183,7 +183,7 @@ export class BaseChart extends CompilableBase implements I constructor(spec: T, option: IChartOption) { super(option); - this._paddingSpec = normalizeLayoutPaddingSpec(spec.padding ?? option.getTheme().padding); + this._paddingSpec = normalizeLayoutPaddingSpec(spec.padding ?? option.getTheme('padding')); this._event = new Event(option.eventDispatcher, option.mode); this._dataSet = option.dataSet; @@ -838,7 +838,7 @@ export class BaseChart extends CompilableBase implements I updateChartConfig(result: IUpdateSpecResult, oldSpec: IChartSpec) { // padding; - this._paddingSpec = normalizeLayoutPaddingSpec(this._spec.padding ?? this._option?.getTheme().padding); + this._paddingSpec = normalizeLayoutPaddingSpec(this._spec.padding ?? this._option?.getTheme('padding')); // re compute padding & layout this._updateLayoutRect(this._viewBox); @@ -1343,6 +1343,6 @@ export class BaseChart extends CompilableBase implements I } getColorScheme() { - return this._option.getTheme?.().colorScheme; + return this._option.getTheme?.('colorScheme'); } } diff --git a/packages/vchart/src/component/axis/util.ts b/packages/vchart/src/component/axis/util.ts index b54f600e6e..7aa0cca71c 100644 --- a/packages/vchart/src/component/axis/util.ts +++ b/packages/vchart/src/component/axis/util.ts @@ -5,7 +5,6 @@ import type { AxisType, ICommonAxisSpec, ILinearAxisSpec } from './interface'; import { transformComponentStyle } from '../../util/style'; import { isXAxis, isYAxis } from './cartesian/util/common'; import { getComponentThemeFromOption } from '../util'; -import type { ITheme } from '../../theme'; import type { IAxisHelper } from './cartesian'; import type { IPolarAxisHelper } from './polar'; @@ -67,33 +66,33 @@ export function isValidPolarAxis(spec: any) { return orient === 'angle' || orient === 'radius'; } -export const getCartesianAxisTheme = (orient: IOrientType, type: AxisType, chartTheme: ITheme) => { +export const getCartesianAxisTheme = (orient: IOrientType, type: AxisType, getTheme: (...keys: string[]) => any) => { const axisTypeTheme = (type === 'band' - ? getComponentThemeFromOption('axisBand', chartTheme) + ? getComponentThemeFromOption('axisBand', getTheme) : (['linear', 'log', 'symlog'] as AxisType[]).includes(type) - ? getComponentThemeFromOption('axisLinear', chartTheme) + ? getComponentThemeFromOption('axisLinear', getTheme) : {}) ?? {}; const axisTheme = isXAxis(orient) - ? getComponentThemeFromOption('axisX', chartTheme) + ? getComponentThemeFromOption('axisX', getTheme) : isYAxis(orient) - ? getComponentThemeFromOption('axisY', chartTheme) - : getComponentThemeFromOption('axisZ', chartTheme); - return mergeSpec({}, getComponentThemeFromOption('axis', chartTheme), axisTypeTheme, axisTheme); + ? getComponentThemeFromOption('axisY', getTheme) + : getComponentThemeFromOption('axisZ', getTheme); + return mergeSpec({}, getComponentThemeFromOption('axis', getTheme), axisTypeTheme, axisTheme); }; -export const getPolarAxisTheme = (orient: IPolarOrientType, type: AxisType, chartTheme: ITheme) => { +export const getPolarAxisTheme = (orient: IPolarOrientType, type: AxisType, getTheme: (...keys: string[]) => any) => { const axisTypeTheme = (type === 'band' - ? getComponentThemeFromOption('axisBand', chartTheme) + ? getComponentThemeFromOption('axisBand', getTheme) : type === 'linear' - ? getComponentThemeFromOption('axisLinear', chartTheme) + ? getComponentThemeFromOption('axisLinear', getTheme) : {}) ?? {}; const axisTheme = orient === 'angle' - ? getComponentThemeFromOption('axisAngle', chartTheme) - : getComponentThemeFromOption('axisRadius', chartTheme); - return mergeSpec({}, getComponentThemeFromOption('axis', chartTheme), axisTypeTheme, axisTheme); + ? getComponentThemeFromOption('axisAngle', getTheme) + : getComponentThemeFromOption('axisRadius', getTheme); + return mergeSpec({}, getComponentThemeFromOption('axis', getTheme), axisTypeTheme, axisTheme); }; export const isDiscreteAxis = (axisType: AxisType) => diff --git a/packages/vchart/src/component/base/base-component-transformer.ts b/packages/vchart/src/component/base/base-component-transformer.ts index bd157cc9b7..2b81e334e5 100644 --- a/packages/vchart/src/component/base/base-component-transformer.ts +++ b/packages/vchart/src/component/base/base-component-transformer.ts @@ -9,7 +9,7 @@ export class BaseComponentSpecTransformer< K = any > extends BaseModelSpecTransformer { getTheme(spec: T, chartSpec: any): K { - return getComponentThemeFromGlobalTheme(this.type as ComponentTypeEnum, this._option.getTheme(), spec, chartSpec); + return getComponentThemeFromGlobalTheme(this.type as ComponentTypeEnum, this._option.getTheme, spec, chartSpec); } protected _mergeThemeToSpec(spec: T, chartSpec: any): { spec: T; theme: K } { diff --git a/packages/vchart/src/component/base/util.ts b/packages/vchart/src/component/base/util.ts index 85cc0f5570..369c6ad44e 100644 --- a/packages/vchart/src/component/base/util.ts +++ b/packages/vchart/src/component/base/util.ts @@ -10,40 +10,40 @@ import { mergeSpec } from '@visactor/vutils-extension'; export function getComponentThemeFromGlobalTheme( type: ComponentTypeEnum, - chartTheme: ITheme, + getTheme: (...key: string[]) => any, componentSpec: any, chartSpec: any ) { switch (type) { case ComponentTypeEnum.cartesianBandAxis: - return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'band', chartTheme); + return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'band', getTheme); case ComponentTypeEnum.cartesianLinearAxis: - return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'linear', chartTheme); + return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'linear', getTheme); case ComponentTypeEnum.cartesianLogAxis: - return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'log', chartTheme); + return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'log', getTheme); case ComponentTypeEnum.cartesianSymlogAxis: - return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'symlog', chartTheme); + return getCartesianAxisTheme(getOrient(componentSpec, ['z']), 'symlog', getTheme); case ComponentTypeEnum.cartesianAxis: case ComponentTypeEnum.cartesianTimeAxis: - return getCartesianAxisTheme(getOrient(componentSpec), undefined, chartTheme); + return getCartesianAxisTheme(getOrient(componentSpec), undefined, getTheme); case ComponentTypeEnum.polarBandAxis: - return getPolarAxisTheme(componentSpec.orient, 'band', chartTheme); + return getPolarAxisTheme(componentSpec.orient, 'band', getTheme); case ComponentTypeEnum.polarLinearAxis: - return getPolarAxisTheme(componentSpec.orient, 'linear', chartTheme); + return getPolarAxisTheme(componentSpec.orient, 'linear', getTheme); case ComponentTypeEnum.polarAxis: - return getPolarAxisTheme(componentSpec.orient, undefined, chartTheme); + return getPolarAxisTheme(componentSpec.orient, undefined, getTheme); case ComponentTypeEnum.cartesianCrosshair: - return getCartesianCrosshairTheme(chartTheme, chartSpec); + return getCartesianCrosshairTheme(getTheme, chartSpec); case ComponentTypeEnum.polarCrosshair: - return getPolarCrosshairTheme(chartTheme, chartSpec); + return getPolarCrosshairTheme(getTheme, chartSpec); case ComponentTypeEnum.colorLegend: case ComponentTypeEnum.sizeLegend: case ComponentTypeEnum.discreteLegend: case ComponentTypeEnum.dataZoom: case ComponentTypeEnum.scrollBar: - return getComponentThemeWithDirection(componentSpec, getComponentThemeFromOption(type, chartTheme)); + return getComponentThemeWithDirection(componentSpec, getComponentThemeFromOption(type, getTheme)); default: - return getComponentThemeFromOption(type, chartTheme); + return getComponentThemeFromOption(type, getTheme); } } diff --git a/packages/vchart/src/component/crosshair/utils/common.ts b/packages/vchart/src/component/crosshair/utils/common.ts index fa1079acf6..441250f13d 100644 --- a/packages/vchart/src/component/crosshair/utils/common.ts +++ b/packages/vchart/src/component/crosshair/utils/common.ts @@ -9,7 +9,6 @@ import { isDiscrete } from '@visactor/vscale'; import type { ICartesianAxisCommonSpec, IPolarAxisCommonSpec } from '../../axis'; import { getComponentThemeFromOption } from '../../util'; import { ComponentTypeEnum } from '../../interface/type'; -import type { ITheme } from '../../../theme'; import { isDiscreteAxis } from '../../axis/util'; import { mergeSpec } from '@visactor/vutils-extension'; @@ -72,10 +71,10 @@ export function getDatumByValue(data: Datum[], value: number, startField: string return null; } -export const getCartesianCrosshairTheme = (chartTheme: ITheme, chartSpec: any): ICrosshairTheme => { +export const getCartesianCrosshairTheme = (getTheme: (...keys: string[]) => any, chartSpec: any): ICrosshairTheme => { const axes: ICartesianAxisCommonSpec[] = array(chartSpec.axes ?? []); const { bandField, linearField, xField, yField } = - getComponentThemeFromOption(ComponentTypeEnum.crosshair, chartTheme) ?? {}; + getComponentThemeFromOption(ComponentTypeEnum.crosshair, getTheme) ?? {}; const xAxis = axes.find(axis => isXAxis(axis.orient)); let newXField; @@ -99,10 +98,10 @@ export const getCartesianCrosshairTheme = (chartTheme: ITheme, chartSpec: any): }; }; -export const getPolarCrosshairTheme = (chartTheme: ITheme, chartSpec: any): ICrosshairTheme => { +export const getPolarCrosshairTheme = (getTheme: (...keys: string[]) => any, chartSpec: any): ICrosshairTheme => { const axes: IPolarAxisCommonSpec[] = array(chartSpec.axes ?? []); const { bandField, linearField, categoryField, valueField } = - getComponentThemeFromOption(ComponentTypeEnum.crosshair, chartTheme) ?? {}; + getComponentThemeFromOption(ComponentTypeEnum.crosshair, getTheme) ?? {}; const angleAxis = axes.find(axis => axis.orient === 'angle'); let newAngleField; diff --git a/packages/vchart/src/component/util.ts b/packages/vchart/src/component/util.ts index 3dc3312dce..1488121325 100644 --- a/packages/vchart/src/component/util.ts +++ b/packages/vchart/src/component/util.ts @@ -1,12 +1,11 @@ import type { Maybe } from '@visactor/vutils'; -import { get, isArray, isNil } from '@visactor/vutils'; -import type { ITheme } from '../theme'; +import { isArray, isNil } from '@visactor/vutils'; import type { Datum } from '../typings'; import { Factory } from '../core/factory'; import type { IModelSpecInfo } from '../model/interface'; -export function getComponentThemeFromOption(type: string, chartTheme: ITheme) { - return get(chartTheme, `component.${type}`); +export function getComponentThemeFromOption(type: string, getTheme: (...keys: string[]) => any) { + return getTheme('component', type); } export function getFormatFunction( diff --git a/packages/vchart/src/core/vchart.ts b/packages/vchart/src/core/vchart.ts index 8dded139e8..2750adcaa7 100644 --- a/packages/vchart/src/core/vchart.ts +++ b/packages/vchart/src/core/vchart.ts @@ -98,6 +98,7 @@ import type { } from './interface'; import { InstanceManager } from './instance-manager'; import type { IAxis } from '../component/axis'; +import type { PopTipAttributes } from '@visactor/vrender-components'; import { setPoptipTheme } from '@visactor/vrender-components'; import { calculateChartSize, mergeUpdateResult } from '../chart/util'; import { Region } from '../region/region'; @@ -361,6 +362,7 @@ export class VChart implements IVChart { private _currentThemeName: string; private _currentTheme: ITheme; + private _cachedProcessedTheme: ITheme; private _onError?: (...args: any[]) => void; @@ -444,7 +446,7 @@ export class VChart implements IVChart { this._compiler.initView(); // TODO: 如果通过 updateSpec 更新主题字体的验证 // 设置全局字体 - this._setFontFamilyTheme(this._currentTheme?.fontFamily as string); + this._setFontFamilyTheme(this.getTheme('fontFamily') as string); this._initDataSet(this._option.dataSet); this._autoSize = isTrueBrowseEnv ? spec.autoFit ?? this._option.autoFit ?? true : false; this._bindResizeEvent(); @@ -692,7 +694,7 @@ export class VChart implements IVChart { // 卸载了chart之后再设置主题 避免多余的reInit if (updateResult.changeTheme) { this._setCurrentTheme(); - this._setFontFamilyTheme(this._currentTheme?.fontFamily as string); + this._setFontFamilyTheme(this.getTheme('fontFamily') as string); } else if (updateResult.changeBackground) { this._compiler?.setBackground(this._getBackground()); } @@ -855,6 +857,7 @@ export class VChart implements IVChart { this._onResize = null; this._container = null; this._currentTheme = null; + this._cachedProcessedTheme = null; this._option = null; this._chart = null; this._compiler = null; @@ -1466,9 +1469,9 @@ export class VChart implements IVChart { ) { const finalTheme = mergeTheme( {}, - getThemeObject(this._currentThemeName, true), - getThemeObject(optionTheme, true), - getThemeObject(specTheme, true) + getThemeObject(this._currentThemeName), + getThemeObject(optionTheme), + getThemeObject(specTheme) ); this._currentTheme = processThemeByChartType(chartType, finalTheme); @@ -1479,15 +1482,16 @@ export class VChart implements IVChart { getThemeObject(optionTheme), getThemeObject(specTheme) ); - this._currentTheme = preprocessTheme(processThemeByChartType(chartType, finalTheme)); + this._currentTheme = processThemeByChartType(chartType, finalTheme); } } else { - currentTheme = getThemeObject(this._currentThemeName, true); + currentTheme = getThemeObject(this._currentThemeName); this._currentTheme = processThemeByChartType(chartType, currentTheme); } + this._cachedProcessedTheme = null; // 设置 poptip 的主题 - setPoptipTheme(get(this._currentTheme, 'component.poptip')); + setPoptipTheme(this.getTheme('component', 'poptip') as PopTipAttributes); // 设置背景色 this._compiler?.setBackground(this._getBackground()); } @@ -1521,7 +1525,7 @@ export class VChart implements IVChart { ? this._spec.background : null; // spec > spec.theme > initOptions.theme - return specBackground || (this._currentTheme.background as string) || this._option.background; + return specBackground || this.getTheme('background') || this._option.background; } /** @@ -1559,7 +1563,7 @@ export class VChart implements IVChart { return this as unknown as IVChart; } const result = this._setCurrentTheme(name); - this._setFontFamilyTheme(this._currentTheme?.fontFamily as string); + this._setFontFamilyTheme(this.getTheme('fontFamily') as string); this.updateCustomConfigAndRerender(result, true, { transformSpec: false, actionSource: 'setCurrentTheme' @@ -2155,6 +2159,41 @@ export class VChart implements IVChart { return this._option.mode || RenderModeEnum['desktop-browser']; } + protected getTheme = (...keys: string[]): any => { + if (!this._currentTheme || !keys || !keys.length) { + return undefined; + } + if (!this._cachedProcessedTheme) { + this._cachedProcessedTheme = {}; + } + + const cacheKey = keys.join('.'); + + if ((this._cachedProcessedTheme as any)[cacheKey]) { + return (this._cachedProcessedTheme as any)[cacheKey]; + } + let theme: any = this._currentTheme; + keys.forEach((key: string, index: number) => { + if (theme && isValid(key)) { + theme = (theme as any)[key]; + + if (index === keys.length - 1 && isValid(theme)) { + theme = preprocessTheme( + { + [key]: theme + }, + this._currentTheme.colorScheme, + this._currentTheme.token + )[key]; + } + } + }); + + (this._cachedProcessedTheme as any)[cacheKey] = theme; + + return theme; + }; + protected _getChartOption(type: string): IChartOption { return { type, @@ -2170,7 +2209,7 @@ export class VChart implements IVChart { performanceHook: this._option.performanceHook, viewBox: this._viewBox, animation: this._option.animation, - getTheme: () => this._currentTheme ?? {}, + getTheme: this.getTheme, getSpecInfo: () => this._specInfo ?? {}, layout: this._option.layout, diff --git a/packages/vchart/src/model/base-model.ts b/packages/vchart/src/model/base-model.ts index ae28eab5f1..afeea6ac0a 100644 --- a/packages/vchart/src/model/base-model.ts +++ b/packages/vchart/src/model/base-model.ts @@ -288,7 +288,7 @@ export abstract class BaseModel extends CompilableBase imp } getColorScheme() { - return this._option.getTheme?.().colorScheme; + return this._option.getTheme?.('colorScheme'); } getSpecInfo() { diff --git a/packages/vchart/src/model/interface.ts b/packages/vchart/src/model/interface.ts index 4de0eadbdd..137c94c16f 100644 --- a/packages/vchart/src/model/interface.ts +++ b/packages/vchart/src/model/interface.ts @@ -169,7 +169,7 @@ export interface IModelOption extends ICompilableInitOption { specPath?: Array; specInfoPath?: Array; - getTheme?: () => ITheme; + getTheme?: (...keys: string[]) => any; getSpecInfo?: () => IChartSpecInfo; getChartLayoutRect: () => IRect; getChartViewRect: () => ILayoutRect; diff --git a/packages/vchart/src/plugin/components/tooltip-handler/canvas-tooltip-handler.ts b/packages/vchart/src/plugin/components/tooltip-handler/canvas-tooltip-handler.ts index 72898b5c49..06763aff6f 100644 --- a/packages/vchart/src/plugin/components/tooltip-handler/canvas-tooltip-handler.ts +++ b/packages/vchart/src/plugin/components/tooltip-handler/canvas-tooltip-handler.ts @@ -63,8 +63,8 @@ export class CanvasTooltipHandler extends BaseTooltipHandler { // 计算 tooltip 内容区域的宽高,并缓存结果 protected _getTooltipBoxSize(actualTooltip: ITooltipActual, changePositionOnly: boolean): IContainerSize | undefined { if (!changePositionOnly || isNil(this._attributes)) { - const chartTheme = this._chartOption?.getTheme() ?? {}; - this._attributes = getTooltipAttributes(actualTooltip, this._component.getSpec(), chartTheme); + const globalFontFamily = this._chartOption?.getTheme('fontFamily'); + this._attributes = getTooltipAttributes(actualTooltip, this._component.getSpec(), globalFontFamily); } const { panel } = this._attributes ?? {}; // canvas模式下, size需要考虑border size, 目的是为了精准判断边界是否超出画布,达到confine效果 diff --git a/packages/vchart/src/plugin/components/tooltip-handler/dom-tooltip-handler.ts b/packages/vchart/src/plugin/components/tooltip-handler/dom-tooltip-handler.ts index e59b1bcaac..665e6dbb92 100644 --- a/packages/vchart/src/plugin/components/tooltip-handler/dom-tooltip-handler.ts +++ b/packages/vchart/src/plugin/components/tooltip-handler/dom-tooltip-handler.ts @@ -88,7 +88,7 @@ export class DomTooltipHandler extends BaseTooltipHandler { initRootDom() { const tooltipSpec = this._component.getSpec() as ITooltipSpec; const tooltipElement = document.createElement('div'); - const globalTheme = this._chartOption?.getTheme() ?? {}; + const themeFontFamily = this._chartOption?.getTheme('fontFamily'); setStyleToDom(tooltipElement, { left: '0', @@ -97,7 +97,7 @@ export class DomTooltipHandler extends BaseTooltipHandler { padding: '12px', position: 'absolute', zIndex: DEFAULT_TOOLTIP_Z_INDEX, - fontFamily: (globalTheme?.fontFamily ?? token.fontFamily) as string, + fontFamily: (themeFontFamily ?? token.fontFamily) as string, fontSize: '11px', borderRadius: '3px', borderStyle: 'solid', diff --git a/packages/vchart/src/plugin/components/tooltip-handler/utils/attribute.ts b/packages/vchart/src/plugin/components/tooltip-handler/utils/attribute.ts index 66b03c3390..f6d1b3f597 100644 --- a/packages/vchart/src/plugin/components/tooltip-handler/utils/attribute.ts +++ b/packages/vchart/src/plugin/components/tooltip-handler/utils/attribute.ts @@ -71,7 +71,7 @@ export const measureTooltipText = (text: string | TooltipRichTextAttrs, style: I export function getTextAttributes( style: ITooltipTextTheme = {}, - globalTheme?: ITheme, + globalFontFamily?: string, defaultAttributes?: Partial ): ITooltipTextStyle { const attrs: ITooltipTextStyle = { @@ -79,7 +79,7 @@ export function getTextAttributes( fill: (style.fill ?? style.fontColor) as string, textAlign: style.textAlign, textBaseline: style.textBaseline, - fontFamily: style.fontFamily ?? (globalTheme?.fontFamily as string), + fontFamily: style.fontFamily ?? globalFontFamily, fontSize: style.fontSize as number, fontWeight: style.fontWeight, lineHeight: style.lineHeight as number, @@ -121,7 +121,7 @@ export const getPanelAttributes = (style: ITooltipTheme['panel']): TooltipPanelA export const getTooltipAttributes = ( actualTooltip: ITooltipActual, spec: ITooltipSpec, - globalTheme: ITheme + globalFontFamily?: string ): ITooltipAttributes => { const { style = {}, enterable, transitionDuration } = spec; const { panel = {}, titleLabel, shape, keyLabel, valueLabel, spaceRow: commonSpaceRow, align } = style; @@ -133,16 +133,16 @@ export const getTooltipAttributes = ( textAlign: align === 'right' ? 'right' : 'left', ...titleLabel }, - globalTheme + globalFontFamily ); const keyStyle = getTextAttributes( { textAlign: align === 'right' ? 'right' : 'left', ...keyLabel }, - globalTheme + globalFontFamily ); - const valueStyle = getTextAttributes(valueLabel, globalTheme); + const valueStyle = getTextAttributes(valueLabel, globalFontFamily); const shapeStyle: TooltipRowStyleAttrs['shape'] = { fill: true, size: shape?.size ?? 8, diff --git a/packages/vchart/src/series/base/base-series-transformer.ts b/packages/vchart/src/series/base/base-series-transformer.ts index 0f0ead2ad8..bf01c6a27f 100644 --- a/packages/vchart/src/series/base/base-series-transformer.ts +++ b/packages/vchart/src/series/base/base-series-transformer.ts @@ -38,20 +38,18 @@ export class BaseSeriesSpecTransformer extends BaseMod getTheme(spec: T, chartSpec: any): K { const direction = getDirectionFromSeriesSpec(spec); - const chartTheme = this._option?.getTheme(); - const { markByName, mark } = chartTheme; + const getTheme = this._option?.getTheme; + // const { markByName, mark } = chartTheme; const type = this._option.type; // 基本主题 const seriesMarkMap = Factory.getSeriesMarkMap(type); - const theme = seriesMarkMap - ? transformSeriesThemeToMerge(get(chartTheme, `series.${type}`), type, mark, markByName) - : {}; + const theme = seriesMarkMap ? transformSeriesThemeToMerge(getTheme('series', type), type, getTheme) : {}; // 区分方向的主题 - const themeWithDirection = get(chartTheme, `series.${type}_${direction}`); + const themeWithDirection = getTheme('series', `${type}_${direction}`); // stack 状态下的主题 const stack = this.stack ?? themeWithDirection?.stack ?? theme?.stack; - const themeWithStack = stack ? get(chartTheme, `series.${type}_stack`) : undefined; + const themeWithStack = stack ? getTheme('series', `${type}_stack`) : undefined; return mergeSpec({}, theme, themeWithDirection, themeWithStack); } diff --git a/packages/vchart/src/series/word-cloud/base.ts b/packages/vchart/src/series/word-cloud/base.ts index 934b6bcb12..f9e0efd360 100644 --- a/packages/vchart/src/series/word-cloud/base.ts +++ b/packages/vchart/src/series/word-cloud/base.ts @@ -126,7 +126,7 @@ export class BaseWordCloudSeries = { @@ -20,9 +20,8 @@ export const defaultThemeName = lightTheme.name; export const themes: Map = new Map(Object.keys(builtinThemes).map(key => [key, builtinThemes[key]])); /** 全局已将 token 转换的主题 map (包含用户新注册的主题) */ -const transformedThemes: Map = new Map( - Object.keys(builtinThemes).map(key => [key, preprocessTheme(builtinThemes[key])] as [string, ITheme]) -); +const transformedThemes: Map = new Map(); +// Object.keys(builtinThemes).map(key => [key, preprocessTheme(builtinThemes[key])] as [string, ITheme]) /** 主题 map 中的元素是否 merge 过默认主题 (非默认主题的其他内置主题没有 merge 过默认主题) */ export const hasThemeMerged: Map = new Map( @@ -37,7 +36,7 @@ export const registerTheme = (name: string, theme: Partial) => { // 所有主题基于默认主题扩展,保证基础值 const mergedTheme = getMergedTheme(theme); themes.set(name, mergedTheme); - transformedThemes.set(name, preprocessTheme(mergedTheme)); + hasThemeMerged.set(name, true); }; /** @@ -46,16 +45,12 @@ export const registerTheme = (name: string, theme: Partial) => { * @param transformed 是否获取 token 转换后的主题 * @returns 返回主题 */ -export const getTheme = (name: string = defaultThemeName, transformed: boolean = false) => { +export const getTheme = (name: string = defaultThemeName) => { if (hasThemeMerged.has(name) && !hasThemeMerged.get(name)) { // 重新 merge 默认主题 registerTheme(name, themes.get(name)); } - if (transformed) { - return transformedThemes.get(name); - } - return themes.get(name); }; diff --git a/packages/vchart/src/theme/color-scheme/util.ts b/packages/vchart/src/theme/color-scheme/util.ts index 58e9ee40bf..a8a1433e77 100644 --- a/packages/vchart/src/theme/color-scheme/util.ts +++ b/packages/vchart/src/theme/color-scheme/util.ts @@ -133,9 +133,9 @@ export function queryColorFromColorScheme( } /** 查询语义化颜色 */ -export const getActualColor = (value: any, colorScheme?: IThemeColorScheme, seriesSpec?: ISeriesSpec) => { +export const getActualColor = (value: any, colorScheme?: IThemeColorScheme) => { if (colorScheme && isColorKey(value)) { - const color = queryColorFromColorScheme(colorScheme, value, seriesSpec); + const color = queryColorFromColorScheme(colorScheme, value); if (color) { return color; } diff --git a/packages/vchart/src/theme/theme-manager.ts b/packages/vchart/src/theme/theme-manager.ts index 6892bfb0cb..90cc264dcf 100644 --- a/packages/vchart/src/theme/theme-manager.ts +++ b/packages/vchart/src/theme/theme-manager.ts @@ -25,7 +25,7 @@ export class ThemeManager { * @returns */ static getTheme(name: string, transformed: boolean = false) { - return getTheme(name, transformed); + return getTheme(name); } /** diff --git a/packages/vchart/src/util/theme/common.ts b/packages/vchart/src/util/theme/common.ts index 484b2fb331..4ffa8433b2 100644 --- a/packages/vchart/src/util/theme/common.ts +++ b/packages/vchart/src/util/theme/common.ts @@ -3,10 +3,10 @@ import type { ITheme } from '../../theme'; import { ThemeManager } from '../../theme'; import { isObject, isString } from '@visactor/vutils'; -export function getThemeObject(theme?: string | ITheme, transformed?: boolean): ITheme { +export function getThemeObject(theme?: string | ITheme): ITheme { if (isString(theme)) { if (ThemeManager.themeExist(theme)) { - return ThemeManager.getTheme(theme, transformed); + return ThemeManager.getTheme(theme); } return {}; } else if (isObject(theme)) { diff --git a/packages/vchart/src/util/theme/merge-theme.ts b/packages/vchart/src/util/theme/merge-theme.ts index 7b91c63f10..38791bfa64 100644 --- a/packages/vchart/src/util/theme/merge-theme.ts +++ b/packages/vchart/src/util/theme/merge-theme.ts @@ -44,8 +44,7 @@ export function transformColorSchemeToMerge(colorScheme?: Maybe any ): any { const seriesMarkInfoMap = Factory.getSeriesMarkMap(seriesType); @@ -54,7 +53,7 @@ export function transformSeriesThemeToMerge( } const newTheme: any = {}; Object.values(seriesMarkInfoMap).forEach(({ type, name }) => { - newTheme[name] = mergeSpec({}, markByType?.[array(type)[0]], markByName?.[name], seriesTheme?.[name]); + newTheme[name] = mergeSpec({}, getTheme('mark', array(type)[0]), getTheme('markByName', name), seriesTheme?.[name]); }); return { ...seriesTheme, diff --git a/packages/vchart/src/util/theme/preprocess.ts b/packages/vchart/src/util/theme/preprocess.ts index fc59e99960..dec4f88c7a 100644 --- a/packages/vchart/src/util/theme/preprocess.ts +++ b/packages/vchart/src/util/theme/preprocess.ts @@ -1,7 +1,6 @@ import { isPlainObject } from '@visactor/vutils'; import type { IThemeColorScheme } from '../../theme/color-scheme/interface'; import { getActualColor, isColorKey } from '../../theme/color-scheme/util'; -import type { ISeriesSpec } from '../../typings'; import type { TokenMap } from '../../theme/token'; // eslint-disable-next-line no-duplicate-imports import { isTokenKey, queryToken } from '../../theme/token'; @@ -9,12 +8,7 @@ import type { ITheme } from '../../theme'; const IGNORE_KEYS = ['animationThreshold', 'colorScheme', 'name', 'padding']; -export function preprocessTheme( - obj: any, - colorScheme?: IThemeColorScheme, - tokenMap?: TokenMap, - seriesSpec?: ISeriesSpec -): any { +export function preprocessTheme(obj: any, colorScheme?: IThemeColorScheme, tokenMap?: TokenMap): any { if (!obj) { return obj; } @@ -28,19 +22,19 @@ export function preprocessTheme( Object.keys(obj).forEach(key => { const value = obj[key]; if (IGNORE_KEYS.includes(key)) { - newObj[key] = value; + (newObj as any)[key] = value; } else if (isPlainObject(value)) { if (isColorKey(value)) { // 查询、替换语义化颜色 - newObj[key] = getActualColor(value, colorScheme, seriesSpec); + (newObj as any)[key] = getActualColor(value, colorScheme); } else if (isTokenKey(value)) { // 查询、替换语义化 token - newObj[key] = queryToken(tokenMap, value); + (newObj as any)[key] = queryToken(tokenMap, value); } else { - newObj[key] = preprocessTheme(value, colorScheme, tokenMap, seriesSpec); + (newObj as any)[key] = preprocessTheme(value, colorScheme, tokenMap); } } else { - newObj[key] = value; + (newObj as any)[key] = value; } }); From 78c96e19f84d5b9ca7e850543fd5e9d1f3967b87 Mon Sep 17 00:00:00 2001 From: xile611 Date: Wed, 5 Feb 2025 19:53:49 +0800 Subject: [PATCH 2/3] docs: update changlog of rush --- ...-theme-of-visible-components_2025-02-05-11-53.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@visactor/vchart/perf-parse-theme-of-visible-components_2025-02-05-11-53.json diff --git a/common/changes/@visactor/vchart/perf-parse-theme-of-visible-components_2025-02-05-11-53.json b/common/changes/@visactor/vchart/perf-parse-theme-of-visible-components_2025-02-05-11-53.json new file mode 100644 index 0000000000..5d81f55e76 --- /dev/null +++ b/common/changes/@visactor/vchart/perf-parse-theme-of-visible-components_2025-02-05-11-53.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "refactor: optimize the process of theme\n\n", + "type": "none", + "packageName": "@visactor/vchart" + } + ], + "packageName": "@visactor/vchart", + "email": "dingling112@gmail.com" +} \ No newline at end of file From d8ee917337ed88320cf86d35cf9e3865f17267e2 Mon Sep 17 00:00:00 2001 From: xile611 Date: Thu, 6 Feb 2025 10:50:15 +0800 Subject: [PATCH 3/3] test: update test case about `getTheme` --- .../vchart/__tests__/unit/chart/bar.test.ts | 10 +++---- .../__tests__/unit/chart/histogram.test.ts | 8 ++--- .../vchart/__tests__/unit/chart/line.test.ts | 14 ++++----- .../unit/chart/linearProgress.test.ts | 8 ++--- .../__tests__/unit/chart/rangeColumn.test.ts | 8 ++--- .../__tests__/unit/chart/treemap.test.ts | 8 ++--- .../__tests__/unit/chart/word-cloud.test.ts | 8 ++--- .../cartesian/axis/linear-axis.test.ts | 30 +++++++++---------- .../vchart/__tests__/unit/data/fields.test.ts | 16 +++++----- .../vchart/__tests__/unit/morph/morph.test.ts | 16 +++++----- .../__tests__/unit/scale/global-scale.test.ts | 11 +++---- packages/vchart/__tests__/util/context.ts | 29 ++++++++++++++++-- 12 files changed, 95 insertions(+), 71 deletions(-) diff --git a/packages/vchart/__tests__/unit/chart/bar.test.ts b/packages/vchart/__tests__/unit/chart/bar.test.ts index b90c76e915..42aee60f1c 100644 --- a/packages/vchart/__tests__/unit/chart/bar.test.ts +++ b/packages/vchart/__tests__/unit/chart/bar.test.ts @@ -2,12 +2,12 @@ import { GlobalScale } from '../../../src/scale/global-scale'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import { EventDispatcher } from '../../../src/event/event-dispatcher'; -import type { BarSeries, IChartSpec } from '../../../src'; +import type { BarSeries } from '../../../src'; // eslint-disable-next-line no-duplicate-imports -import { BarChart, ThemeManager } from '../../../src'; +import { BarChart } from '../../../src'; import { DataSet } from '@visactor/vdataset'; import { createCanvas, removeDom } from '../../util/dom'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; import { getTestCompiler } from '../../util/factory/compiler'; // 保证引入执行 Build-in @@ -92,7 +92,7 @@ describe('Bar chart test', () => { const transformer = new BarChart.transformerConstructor({ type: 'bar', seriesType: 'bar', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -113,7 +113,7 @@ describe('Bar chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any ); diff --git a/packages/vchart/__tests__/unit/chart/histogram.test.ts b/packages/vchart/__tests__/unit/chart/histogram.test.ts index 70a48cb7c8..a0b3d24655 100644 --- a/packages/vchart/__tests__/unit/chart/histogram.test.ts +++ b/packages/vchart/__tests__/unit/chart/histogram.test.ts @@ -1,12 +1,12 @@ import { EventDispatcher } from '../../../src/event/event-dispatcher'; import type { BarSeries } from '../../../src'; // eslint-disable-next-line no-duplicate-imports -import { HistogramChart, ThemeManager } from '../../../src'; +import { HistogramChart } from '../../../src'; import { DataSet, DataView, csvParser } from '@visactor/vdataset'; import { createCanvas, removeDom } from '../../util/dom'; import { getTestCompiler } from '../../util/factory/compiler'; import { GlobalScale } from '../../../src/scale/global-scale'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; // 保证引入执行 Build-in const dataSet = new DataSet(); @@ -53,7 +53,7 @@ describe('histogram chart test', () => { const transformer = new HistogramChart.transformerConstructor({ type: 'histogram', seriesType: 'bar', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -71,7 +71,7 @@ describe('histogram chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any ); diff --git a/packages/vchart/__tests__/unit/chart/line.test.ts b/packages/vchart/__tests__/unit/chart/line.test.ts index 1dcde0d18a..d14c4ad3b6 100644 --- a/packages/vchart/__tests__/unit/chart/line.test.ts +++ b/packages/vchart/__tests__/unit/chart/line.test.ts @@ -2,12 +2,12 @@ import type { ILineChartSpec } from '../../../src/chart/line/interface'; import { GlobalScale } from '../../../src/scale/global-scale'; import type { LineSeries } from '../../../src/series/line/line'; import { DataSet, DataView, csvParser } from '@visactor/vdataset'; -import { LineChart } from '../../../src/chart/line/line'; +import { LineChart, registerLineChart } from '../../../src/chart/line/line'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; import { getTestCompiler } from '../../util/factory/compiler'; -import { initChartDataSet } from '../../util/context'; -import VChart, { ThemeManager } from '../../../src'; +import { getTheme, initChartDataSet } from '../../util/context'; +registerLineChart(); const dataSet = new DataSet(); initChartDataSet(dataSet); dataSet.registerParser('csv', csvParser); @@ -34,7 +34,7 @@ describe('line chart test', () => { const transformer = new LineChart.transformerConstructor({ type: 'line', seriesType: 'line', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -55,7 +55,7 @@ describe('line chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, onError: () => {}, getSpecInfo: () => info } as any @@ -103,7 +103,7 @@ describe('line chart test', () => { const transformer = new LineChart.transformerConstructor({ type: 'line', seriesType: 'line', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -122,7 +122,7 @@ describe('line chart test', () => { mode: 'mobile-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any); chart.created(transformer); diff --git a/packages/vchart/__tests__/unit/chart/linearProgress.test.ts b/packages/vchart/__tests__/unit/chart/linearProgress.test.ts index 38fce1eb37..2394056ae0 100644 --- a/packages/vchart/__tests__/unit/chart/linearProgress.test.ts +++ b/packages/vchart/__tests__/unit/chart/linearProgress.test.ts @@ -2,10 +2,10 @@ import { DataSet, csvParser } from '@visactor/vdataset'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; import type { LinearProgressSeries } from '../../../src'; // eslint-disable-next-line no-duplicate-imports -import { LinearProgressChart, ThemeManager } from '../../../src'; +import { LinearProgressChart } from '../../../src'; import { getTestCompiler } from '../../util/factory/compiler'; import { GlobalScale } from '../../../src/scale/global-scale'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; // 保证引入执行 Build-in const dataSet = new DataSet(); @@ -41,7 +41,7 @@ describe('linearProgress chart test', () => { const transformer = new LinearProgressChart.transformerConstructor({ type: 'linearProgress', seriesType: 'linearProgress', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -59,7 +59,7 @@ describe('linearProgress chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, animation: false, getSpecInfo: () => info } as any diff --git a/packages/vchart/__tests__/unit/chart/rangeColumn.test.ts b/packages/vchart/__tests__/unit/chart/rangeColumn.test.ts index 82a59d1751..28a9501eb1 100644 --- a/packages/vchart/__tests__/unit/chart/rangeColumn.test.ts +++ b/packages/vchart/__tests__/unit/chart/rangeColumn.test.ts @@ -1,10 +1,10 @@ import { DataSet, DataView, csvParser } from '@visactor/vdataset'; -import { RangeColumnChart, ThemeManager } from '../../../src'; +import { RangeColumnChart } from '../../../src'; import type { RangeColumnSeries } from '../../../src/series/range-column/range-column'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; import { getTestCompiler } from '../../util/factory/compiler'; import { GlobalScale } from '../../../src/scale/global-scale'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; // 保证引入执行 Build-in const dataSet = new DataSet(); @@ -51,7 +51,7 @@ describe('rangeColumn chart test', () => { const transformer = new RangeColumnChart.transformerConstructor({ type: 'rangeColumn', seriesType: 'rangeColumn', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -72,7 +72,7 @@ describe('rangeColumn chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, animation: false, getSpecInfo: () => info } as any diff --git a/packages/vchart/__tests__/unit/chart/treemap.test.ts b/packages/vchart/__tests__/unit/chart/treemap.test.ts index 4de64e7871..1885650633 100644 --- a/packages/vchart/__tests__/unit/chart/treemap.test.ts +++ b/packages/vchart/__tests__/unit/chart/treemap.test.ts @@ -2,7 +2,7 @@ import { GlobalScale } from '../../../src/scale/global-scale'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import { EventDispatcher } from '../../../src/event/event-dispatcher'; -import { ThemeManager, default as VChart } from '../../../src'; +import { default as VChart } from '../../../src'; import { DataSet, csvParser } from '@visactor/vdataset'; import { createCanvas, removeDom } from '../../util/dom'; import { getTestCompiler } from '../../util/factory/compiler'; @@ -12,7 +12,7 @@ import type { ITreemapChartSpec } from '../../../src/chart/treemap'; import { TreemapChart } from '../../../src/chart/treemap'; import type { TreemapSeries } from '../../../src/series/treemap/treemap'; import { DEFAULT_HIERARCHY_DEPTH } from '../../../src/constant/hierarchy'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; // 保证引入执行 Build-in const dataSet = new DataSet(); @@ -54,7 +54,7 @@ describe('treemap chart test', () => { const transformer = new TreemapChart.transformerConstructor({ type: 'treemap', seriesType: 'treemap', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -75,7 +75,7 @@ describe('treemap chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, onError: () => {}, getSpecInfo: () => info } as any diff --git a/packages/vchart/__tests__/unit/chart/word-cloud.test.ts b/packages/vchart/__tests__/unit/chart/word-cloud.test.ts index 37cef8aabe..7223681c68 100644 --- a/packages/vchart/__tests__/unit/chart/word-cloud.test.ts +++ b/packages/vchart/__tests__/unit/chart/word-cloud.test.ts @@ -4,14 +4,14 @@ import { GlobalScale } from '../../../src/scale/global-scale'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; import type { IWordCloudChartSpec } from '../../../src'; // eslint-disable-next-line no-duplicate-imports -import { ThemeManager, default as VChart } from '../../../src'; +import { default as VChart } from '../../../src'; import { DataSet, csvParser } from '@visactor/vdataset'; import { WordCloudChart } from '../../../src/chart/word-cloud/word-cloud'; import type { WordCloudSeries } from '../../../src/series/word-cloud/word-cloud'; import { dataWordCloud } from '../../data/data-wordcloud'; import { createCanvas, removeDom } from '../../util/dom'; import { getTestCompiler } from '../../util/factory/compiler'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; // 保证引入执行 Build-in const dataSet = new DataSet(); @@ -62,7 +62,7 @@ describe('wordCloud chart test', () => { const transformer = new WordCloudChart.transformerConstructor({ type: 'wordCloud', seriesType: 'wordCloud', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec); @@ -81,7 +81,7 @@ describe('wordCloud chart test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any); chart.created(transformer); diff --git a/packages/vchart/__tests__/unit/component/cartesian/axis/linear-axis.test.ts b/packages/vchart/__tests__/unit/component/cartesian/axis/linear-axis.test.ts index 6835bded7d..fe4968501e 100644 --- a/packages/vchart/__tests__/unit/component/cartesian/axis/linear-axis.test.ts +++ b/packages/vchart/__tests__/unit/component/cartesian/axis/linear-axis.test.ts @@ -6,11 +6,11 @@ import { DataSet, csvParser } from '@visactor/vdataset'; import { dimensionStatistics } from '../../../../../src/data/transforms/dimension-statistics'; import type { CartesianLinearAxis } from '../../../../../src/index'; // eslint-disable-next-line no-duplicate-imports -import { CartesianAxis, ThemeManager } from '../../../../../src/index'; +import { CartesianAxis } from '../../../../../src/index'; import { ComponentTypeEnum, type IComponent, type IComponentOption } from '../../../../../src/component/interface'; import { EventDispatcher } from '../../../../../src/event/event-dispatcher'; import { getTestCompiler } from '../../../../util/factory/compiler'; -import { initChartDataSet } from '../../../../util/context'; +import { getTheme, initChartDataSet } from '../../../../util/context'; import type { StringOrNumber } from '../../../../../src/typings/common'; import { getCartesianAxisInfo } from '../../../../../src/component/axis/cartesian/util'; import { wilkinsonExtended } from '@visactor/vscale'; @@ -97,7 +97,7 @@ const ctx: IComponentOption = { return { width: 500, height: 500 } as any; }, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getComponentByUserId: function (user_id: string | number): IComponent | undefined { throw new Error('Function not implemented.'); }, @@ -131,7 +131,7 @@ test('config linearAxis.nice default [true] ', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -158,7 +158,7 @@ test('config linearAxis.nice default [true] ', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -185,7 +185,7 @@ test('nice === false ', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -213,7 +213,7 @@ test('zero === false && nice === false ', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -243,7 +243,7 @@ test('zero === true && range is specific ', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); config = transformer.transformSpec(config, {}).spec; @@ -343,7 +343,7 @@ test('expand', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); config = transformer.transformSpec(config, {}).spec; @@ -420,7 +420,7 @@ test('extend', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); config = transformer.transformSpec(config, {}).spec; @@ -475,7 +475,7 @@ test('niceDomain should work when domain is 0, and user does not set min or max' }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -507,7 +507,7 @@ test('niceDomain should not work when user set min or max', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -542,7 +542,7 @@ test('dynamic tickCount', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -600,7 +600,7 @@ test('dynamic tickCount', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; @@ -641,7 +641,7 @@ test('dynamic tickCount with wilkson', () => { }); const transformer = new CartesianAxis.transformerConstructor({ type: 'cartesianAxis-linear', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); spec = transformer.transformSpec(spec, {}).spec; diff --git a/packages/vchart/__tests__/unit/data/fields.test.ts b/packages/vchart/__tests__/unit/data/fields.test.ts index ad3261ce5f..10b2c5ddfd 100644 --- a/packages/vchart/__tests__/unit/data/fields.test.ts +++ b/packages/vchart/__tests__/unit/data/fields.test.ts @@ -1,13 +1,11 @@ -import { LineChart } from '../../../src/chart/line/line'; +import { LineChart, registerLineChart } from '../../../src/chart/line/line'; import { DataSet } from '@visactor/vdataset'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; -import * as bt from '../../../src/vchart-all'; import { getTestCompiler } from '../../util/factory/compiler'; import { GlobalScale } from '../../../src/scale/global-scale'; -import { initChartDataSet } from '../../util/context'; -import { ThemeManager } from '../../../src'; -bt; +import { getTheme, initChartDataSet } from '../../util/context'; +registerLineChart(); const dataSet = new DataSet(); initChartDataSet(dataSet); describe('data fields test', () => { @@ -56,7 +54,7 @@ describe('data fields test', () => { const transformer = new LineChart.transformerConstructor({ type: 'line', seriesType: 'line', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -75,7 +73,7 @@ describe('data fields test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any); chart.created(transformer); @@ -137,7 +135,7 @@ describe('data fields test', () => { const transformer = new LineChart.transformerConstructor({ type: 'line', seriesType: 'line', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec as any); @@ -156,7 +154,7 @@ describe('data fields test', () => { mode: 'desktop-browser', getCompiler: getTestCompiler, globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any); chart.created(transformer); diff --git a/packages/vchart/__tests__/unit/morph/morph.test.ts b/packages/vchart/__tests__/unit/morph/morph.test.ts index 289d78482f..574c243d4b 100644 --- a/packages/vchart/__tests__/unit/morph/morph.test.ts +++ b/packages/vchart/__tests__/unit/morph/morph.test.ts @@ -1,10 +1,10 @@ -import { BarChart, CommonChart, ThemeManager } from '../../../src'; +import { BarChart, CommonChart } from '../../../src'; import { DataSet, DataView, csvParser } from '@visactor/vdataset'; import { EventDispatcher } from '../../../src/event/event-dispatcher'; import { createCanvas, removeDom } from '../../util/dom'; import { getTestCompiler } from '../../util/factory/compiler'; import { GlobalScale } from '../../../src/scale/global-scale'; -import { initChartDataSet } from '../../util/context'; +import { getTheme, initChartDataSet } from '../../util/context'; const dataSet = new DataSet(); initChartDataSet(dataSet); @@ -113,7 +113,7 @@ describe('Bar chart test', () => { test('default morph', () => { const transformer = new CommonChart.transformerConstructor({ type: 'common', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(scatterSpec as any); @@ -135,7 +135,7 @@ describe('Bar chart test', () => { globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), animation: true, onError: () => {}, - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any ); @@ -145,7 +145,7 @@ describe('Bar chart test', () => { const barTransformer = new BarChart.transformerConstructor({ type: 'bar', seriesType: 'bar', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const barInfo = barTransformer.initChartSpec(barSpec as any); @@ -167,7 +167,7 @@ describe('Bar chart test', () => { globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), animation: true, onError: () => {}, - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => barInfo } as any ); @@ -190,7 +190,7 @@ describe('Bar chart test', () => { test('custom morph config', () => { const transformer = new CommonChart.transformerConstructor({ type: 'common', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(multiScatterSeriesSpec as any); @@ -212,7 +212,7 @@ describe('Bar chart test', () => { globalScale: new GlobalScale([], { getAllSeries: () => [] as any[] } as any), animation: true, onError: () => {}, - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, getSpecInfo: () => info } as any ); diff --git a/packages/vchart/__tests__/unit/scale/global-scale.test.ts b/packages/vchart/__tests__/unit/scale/global-scale.test.ts index aeeeb669ef..83d00c21db 100644 --- a/packages/vchart/__tests__/unit/scale/global-scale.test.ts +++ b/packages/vchart/__tests__/unit/scale/global-scale.test.ts @@ -4,13 +4,14 @@ import { CommonChart } from '../../../src/chart/common/common'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import { EventDispatcher } from '../../../src/event/event-dispatcher'; -import { VChart, type IChartSpec, type ScatterSeries, ThemeManager } from '../../../src'; +import { VChart, type ScatterSeries } from '../../../src'; // eslint-disable-next-line no-duplicate-imports import { DataSet, dataViewParser, DataView } from '@visactor/vdataset'; import { createCanvas, removeDom } from '../../util/dom'; import type { IAttrs, VisualScaleType } from '../../../src/mark/interface'; import { dimensionStatistics } from '../../../src/data/transforms/dimension-statistics'; import { getTestCompiler } from '../../util/factory/compiler'; +import { getTheme } from '../../util/context'; const VChartClass = VChart; // 确保引用 vchart 以确保注册所需的图表 // 保证引入执行 Build-in @@ -290,7 +291,7 @@ describe('global-scale test', () => { }); const transformer = new CommonChart.transformerConstructor({ type: 'common', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec); @@ -311,7 +312,7 @@ describe('global-scale test', () => { mode: 'desktop-browser', getSpecInfo: () => info, getCompiler: getTestCompiler, - getTheme: () => ThemeManager.getCurrentTheme(true) + getTheme: getTheme } as any ); chart.created(transformer); @@ -440,7 +441,7 @@ describe('global-scale test', () => { }); const transformer = new CommonChart.transformerConstructor({ type: 'common', - getTheme: () => ThemeManager.getCurrentTheme(true), + getTheme: getTheme, mode: 'desktop-browser' }); const info = transformer.initChartSpec(spec); @@ -461,7 +462,7 @@ describe('global-scale test', () => { mode: 'desktop-browser', getSpecInfo: () => info, getCompiler: getTestCompiler, - getTheme: () => ThemeManager.getCurrentTheme(true) + getTheme: getTheme } as any ); chart.created(transformer); diff --git a/packages/vchart/__tests__/util/context.ts b/packages/vchart/__tests__/util/context.ts index 4f92b7a2bf..b906af2ccd 100644 --- a/packages/vchart/__tests__/util/context.ts +++ b/packages/vchart/__tests__/util/context.ts @@ -14,6 +14,8 @@ import { getTestCompiler } from './factory/compiler'; import { GlobalScale } from '../../src/scale/global-scale'; import type { IRegion } from '../../src/region/interface'; import type { StringOrNumber } from '../../src/typings'; +import { isValid } from '@visactor/vutils'; +import { preprocessTheme } from '../../src/util/theme/preprocess'; export function modelOption(opt: Partial = {}, chart?: TestChart): Partial { return { @@ -51,7 +53,7 @@ export function modelOption(opt: Partial = {}, chart?: TestChart): export function seriesOption(opt: Partial = {}, chart?: TestChart): ISeriesOption { const option = modelOption(opt) as ISeriesOption; option.globalScale = new GlobalScale([], chart as any); - option.getTheme = () => ThemeManager.getCurrentTheme(); + option.getTheme = getTheme; option.region = (chart?.getAllRegions?.()?.[0] ?? new TestRegion({})) as IRegion; option.onError = msg => { console.log(msg); @@ -65,7 +67,7 @@ export function seriesOption(opt: Partial = {}, chart?: TestChart) export function componentOption(opt: Partial = {}, chart: TestChart): IComponentOption { const option = modelOption(opt) as IComponentOption; - option.getTheme = () => ThemeManager.getCurrentTheme(); + option.getTheme = getTheme; // 区域 option.getRegionsInIndex = chart.getRegionsInIndex.bind(chart); option.getRegionsInIds = chart.getRegionsInIds.bind(chart); @@ -108,3 +110,26 @@ export function initChartDataSet(dataSet: DataSet) { dataSet.registerTransform('stackSplit', stackSplit); dataSet.registerTransform('copyDataView', copyDataView); } + +export function getTheme(...keys: string[]) { + const currentTheme = ThemeManager.getCurrentTheme(); + let theme = currentTheme; + + keys.forEach((key: string, index: number) => { + if (theme && isValid(key)) { + theme = (theme as any)[key]; + + if (index === keys.length - 1 && isValid(theme)) { + theme = preprocessTheme( + { + [key]: theme + }, + currentTheme.colorScheme, + currentTheme.token + )[key]; + } + } + }); + + return theme; +}