diff --git a/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-45.json b/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-45.json new file mode 100644 index 0000000000..86d5be124f --- /dev/null +++ b/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-45.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: axis's label, tick's state style supports function", + "type": "patch" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-59.json b/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-59.json new file mode 100644 index 0000000000..718a7d87e1 --- /dev/null +++ b/common/changes/@visactor/vchart/feat-component-state-style-enhancement_2023-07-24-05-59.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: discrete legend's item's style and state style supports function", + "type": "patch" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/packages/vchart/src/component/axis/base-axis.ts b/packages/vchart/src/component/axis/base-axis.ts index d3c7d318ec..3a5532c70c 100644 --- a/packages/vchart/src/component/axis/base-axis.ts +++ b/packages/vchart/src/component/axis/base-axis.ts @@ -20,7 +20,7 @@ import { animationConfig } from '../../animation/utils'; import { DEFAULT_MARK_ANIMATION } from '../../animation/config'; import { degreeToRadian, type LooseFunction } from '@visactor/vutils'; import { DEFAULT_TITLE_STYLE, transformAxisLineStyle } from './utils'; -import { transformStateStyle, transformToGraphic } from '../../util/style'; +import { transformAxisLabelStateStyle, transformStateStyle, transformToGraphic } from '../../util/style'; import type { ITransformOptions } from '@visactor/vdataset'; export abstract class AxisComponent extends BaseComponent implements IAxis { @@ -341,9 +341,8 @@ export abstract class AxisComponent extends BaseComponent implements IAxis { space: spec.label.space, inside: spec.label.inside, style: isFunction(spec.label.style) - ? (datum: Datum, index: number) => { - const style = this._preprocessSpec(spec.label.style(datum.rawValue, index, datum)); - + ? (datum: Datum, index: number, data: Datum[], layer?: number) => { + const style = this._preprocessSpec(spec.label.style(datum.rawValue, index, datum, data, layer)); return transformToGraphic(this._preprocessSpec(merge({}, this._theme.label?.style, style))); } : transformToGraphic(spec.label.style), @@ -352,7 +351,7 @@ export abstract class AxisComponent extends BaseComponent implements IAxis { return spec.label.formatMethod(datum.rawValue, datum); } : null, - state: transformStateStyle(spec.label.state), + state: transformAxisLabelStateStyle(spec.label.state), autoRotate: !!spec.label.autoRotate, autoHide: !!spec.label.autoHide, autoLimit: !!spec.label.autoLimit, @@ -368,9 +367,8 @@ export abstract class AxisComponent extends BaseComponent implements IAxis { inside: spec.tick.inside, alignWithLabel: spec.tick.alignWithLabel, style: isFunction(spec.tick.style) - ? (datum: Datum, index: number) => { - const style = this._preprocessSpec(spec.tick.style(datum.rawValue, index, datum)); - + ? (value: number, index: number, datum: Datum, data: Datum[]) => { + const style = this._preprocessSpec(spec.tick.style(value, index, datum, data)); return transformToGraphic(this._preprocessSpec(merge({}, this._theme.tick?.style, style))); } : transformToGraphic(spec.tick.style), @@ -381,7 +379,12 @@ export abstract class AxisComponent extends BaseComponent implements IAxis { length: spec.subTick.tickSize, inside: spec.subTick.inside, count: spec.subTick.tickCount, - style: transformToGraphic(spec.subTick.style), + style: isFunction(spec.subTick.style) + ? (value: number, index: number, datum: Datum, data: Datum[]) => { + const style = spec.subTick.style(value, index, datum, data); + return transformToGraphic(merge({}, this._theme.subTick?.style, style)); + } + : transformToGraphic(spec.subTick.style), state: transformStateStyle(spec.subTick.state) }, grid: { @@ -392,7 +395,6 @@ export abstract class AxisComponent extends BaseComponent implements IAxis { style: isFunction(spec.grid.style) ? (datum: Datum, index: number) => { const style = spec.grid.style(datum.datum?.rawValue, index, datum.datum); - return transformToGraphic(this._preprocessSpec(merge({}, this._theme.grid?.style, style))); } : transformToGraphic(spec.grid.style) diff --git a/packages/vchart/src/component/axis/interface.ts b/packages/vchart/src/component/axis/interface.ts index 7d499d5961..880fa6daa3 100644 --- a/packages/vchart/src/component/axis/interface.ts +++ b/packages/vchart/src/component/axis/interface.ts @@ -264,7 +264,7 @@ export type ILabel = IAxisItem & { * @param datum 图形数据 * @returns 格式化后的文本 */ - formatMethod?: (text: string | string[], datum?: any) => string | string[]; + formatMethod?: (text: string | string[], datum?: Datum) => string | string[]; /** 标签同 tick 之间的间距 */ space?: number; /** @@ -359,7 +359,7 @@ export type ITitle = IAxisItem & { state?: AxisItemStateStyle>; }; -export type StyleCallback = (value: any, index: number, datum: Datum) => T; +export type StyleCallback = (value: any, index: number, datum: Datum, data: Datum[]) => T; export type AxisType = 'linear' | 'ordinal' | 'band' | 'point' | 'time' | 'log'; export interface IAxisCommonTheme { @@ -376,5 +376,5 @@ export interface IAxisCommonTheme { /** 轴刻度线配置 */ tick?: ITick; /** 轴刻度线配置 */ - subTick?: ITick; + subTick?: ISubTick; } diff --git a/packages/vchart/src/component/axis/utils.ts b/packages/vchart/src/component/axis/utils.ts index 1a543d59a0..c2cfa31391 100644 --- a/packages/vchart/src/component/axis/utils.ts +++ b/packages/vchart/src/component/axis/utils.ts @@ -19,9 +19,9 @@ export const DEFAULT_TITLE_STYLE = { }; export function transformAxisLineStyle(lineCfg: any) { - transformComponentStyle(lineCfg); - transformComponentStyle(lineCfg.startSymbol); - transformComponentStyle(lineCfg.endSymbol); + lineCfg = transformComponentStyle(lineCfg); + lineCfg.startSymbol = transformComponentStyle(lineCfg.startSymbol); + lineCfg.endSymbol = transformComponentStyle(lineCfg.endSymbol); return lineCfg; } diff --git a/packages/vchart/src/component/legend/discrete/interface.ts b/packages/vchart/src/component/legend/discrete/interface.ts index ed88a05d2d..8611b0d2ef 100644 --- a/packages/vchart/src/component/legend/discrete/interface.ts +++ b/packages/vchart/src/component/legend/discrete/interface.ts @@ -4,7 +4,9 @@ import type { ILegendCommonSpec, NoVisibleMarkStyle } from '../interface'; import type { StringOrNumber } from '../../../typings'; export type formatterCallback = (text: StringOrNumber, item: LegendItemDatum, index: number) => any; - +export type LegendItemStyleValue = + | T + | ((item: LegendItemDatum, isSelected: boolean, index: number, allItems: LegendItemDatum[]) => T); export type LegendItemStyle = { /** * 样式配置 @@ -42,7 +44,7 @@ export type IItem = { * 是否展示图例项背景 */ visible?: boolean; - } & LegendItemStyle>; + } & LegendItemStyle>>; /** * 图例项的 shape 图标的配置 */ @@ -53,7 +55,7 @@ export type IItem = { visible?: boolean; /** shape 同后面 label 的间距 */ space?: number; - } & LegendItemStyle>>; + } & LegendItemStyle>>>; /** * 图例项的 label 文本配置 */ @@ -66,7 +68,7 @@ export type IItem = { * 格式化文本函数 */ formatMethod?: formatterCallback; - } & LegendItemStyle>; + } & LegendItemStyle>>; /** * 图例项 value 配置 */ @@ -82,7 +84,7 @@ export type IItem = { * 格式化文本函数 */ formatMethod?: formatterCallback; - } & LegendItemStyle>; + } & LegendItemStyle>>; /** * 聚焦按钮配置 */ diff --git a/packages/vchart/src/component/legend/discrete/util.ts b/packages/vchart/src/component/legend/discrete/util.ts index acaaea9624..0b7043d69a 100644 --- a/packages/vchart/src/component/legend/discrete/util.ts +++ b/packages/vchart/src/component/legend/discrete/util.ts @@ -42,10 +42,10 @@ export function getLegendAttributes(spec: IDiscreteLegendSpec, rect: ILayoutRect if (!isEmpty(item.focusIconStyle)) { transformToGraphic(item.focusIconStyle); } - transformComponentStyle(item.shape); - transformComponentStyle(item.label); - transformComponentStyle(item.value); - transformComponentStyle(item.background); + item.shape = transformComponentStyle(item.shape); + item.label = transformComponentStyle(item.label); + item.value = transformComponentStyle(item.value); + item.background = transformComponentStyle(item.background); if (isPercent(item.maxWidth)) { item.maxWidth = (Number(item.maxWidth.substring(0, item.maxWidth.length - 1)) * rect.width) / 100; diff --git a/packages/vchart/src/util/style.ts b/packages/vchart/src/util/style.ts index 0ae7683f59..ca11309b93 100644 --- a/packages/vchart/src/util/style.ts +++ b/packages/vchart/src/util/style.ts @@ -1,4 +1,6 @@ -import { degreeToRadian, isEmpty, isValid, isValidNumber } from '@visactor/vutils'; +import { degreeToRadian, isEmpty, isFunction } from '@visactor/vutils'; +import type { Datum } from '../typings'; +import type { LegendItemDatum } from '@visactor/vrender-components'; /** * 针对一些可以配置状态样式的属性的转换函数,结构如下: @@ -7,32 +9,66 @@ import { degreeToRadian, isEmpty, isValid, isValidNumber } from '@visactor/vutil * @returns */ export function transformComponentStyle(cfg: any = {}) { - if (!isEmpty(cfg.style)) { - cfg.style = transformToGraphic(cfg.style); + const newConfig = { + ...cfg + }; + + if (isFunction(cfg.style)) { + newConfig.style = (item: LegendItemDatum, isSelected: boolean, index: number, allItems: LegendItemDatum[]) => + transformToGraphic(cfg.style(item, isSelected, index, allItems)); + } else if (!isEmpty(cfg.style)) { + newConfig.style = transformToGraphic(cfg.style); } if (!isEmpty(cfg.state)) { + const newStateStyle = {}; Object.keys(cfg.state).forEach(key => { - if (!isEmpty(cfg.state[key])) { - cfg.state[key] = transformToGraphic(cfg.state[key]); + if (isFunction(cfg.state[key])) { + newStateStyle[key] = (item: LegendItemDatum, isSelected: boolean, index: number, allItems: LegendItemDatum[]) => + transformToGraphic(cfg.state[key](item, isSelected, index, allItems)); + } else if (!isEmpty(cfg.state[key])) { + newStateStyle[key] = transformToGraphic(cfg.state[key]); } }); + newConfig.state = newStateStyle; } - return cfg; + return newConfig; } export function transformStateStyle(stateStyle: any) { if (isEmpty(stateStyle)) { return null; } + const newStateStyle = {}; + Object.keys(stateStyle).forEach(key => { + if (isFunction(stateStyle[key])) { + newStateStyle[key] = (value: any, index: number, datum: Datum, data: Datum[]) => + transformToGraphic(stateStyle[key](value, index, datum, data)); + } else if (!isEmpty(stateStyle[key])) { + newStateStyle[key] = transformToGraphic(stateStyle[key]); + } + }); + + return newStateStyle; +} + +export function transformAxisLabelStateStyle(stateStyle: any) { + if (isEmpty(stateStyle)) { + return null; + } + const newStateStyle = {}; Object.keys(stateStyle).forEach(key => { - if (!isEmpty(stateStyle[key])) { - stateStyle[key] = transformToGraphic(stateStyle[key]); + if (isFunction(stateStyle[key])) { + newStateStyle[key] = (datum: Datum, index: number, data: Datum[], layer?: number) => { + return transformToGraphic(stateStyle[key](datum.rawValue, index, datum, data, layer)); + }; + } else if (!isEmpty(stateStyle[key])) { + newStateStyle[key] = transformToGraphic(stateStyle[key]); } }); - return stateStyle; + return newStateStyle; } export function transformToGraphic(style: any) {