Skip to content

Commit

Permalink
refactor: combine tooltipPattern and tooltipactual
Browse files Browse the repository at this point in the history
  • Loading branch information
xile611 committed Sep 29, 2024
1 parent ce9be8a commit 44ba42f
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 420 deletions.
5 changes: 2 additions & 3 deletions packages/vchart/src/component/tooltip/interface/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ export type TooltipHandlerParams = DimensionEventParams & {
/** tooltip 原始的spec */
tooltipSpec?: ITooltipSpec;
/** TODO: 本次触发的tooltip,主要包含pattern数据,待优化 */
activeTooltipSpec?: Pick<ITooltipSpec, 'activeType' | 'dimension' | 'mark' | 'group' | 'visible' | 'handler'>;
/** 本次触发的 tooltip 的显示数据 */
tooltipActual?: ITooltipActual;
activeTooltipSpec?: ITooltipActual;
// Pick<ITooltipSpec, 'activeType' | 'dimension' | 'mark' | 'group' | 'visible' | 'handler'>;
/** 和 datum 同组的数据项 */
groupDatum?: Datum[];
};
Expand Down
59 changes: 6 additions & 53 deletions packages/vchart/src/component/tooltip/processor/base.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { isNil, isValid } from '@visactor/vutils';
import { isNil } from '@visactor/vutils';
import type { BaseEventParams } from '../../../event/interface';
import type { ITooltipActual, ITooltipPattern, TooltipActiveType, TooltipData } from '../../../typings';
import type { ITooltipSpec, TooltipHandlerParams } from '../interface';
import type { ITooltipActual, TooltipActiveType, TooltipData } from '../../../typings';
import type { TooltipHandlerParams } from '../interface';
// eslint-disable-next-line no-duplicate-imports
import { TooltipResult } from '../interface/common';
import type { Tooltip } from '../tooltip';
Expand All @@ -11,16 +11,13 @@ import type { TooltipEventParams } from '../interface/event';
import type { IDimensionInfo } from '../../../event/events/dimension';
import type { ISeries } from '../../../series/interface';
import { getTooltipSpecForShow } from '../utils/get-spec';
import { getShowContent } from '../utils/compose';
import { getTooltipPatternValue } from '../utils/get-value';
import { isActiveTypeVisible } from '../utils/common';

export abstract class BaseTooltipProcessor {
readonly component: Tooltip;
abstract activeType: TooltipActiveType;

protected _cacheViewSpec: ITooltipSpec | undefined;
protected _cacheActualTooltip: ITooltipActual | undefined;
protected _cacheViewSpec: ITooltipActual | undefined;

constructor(component: Tooltip) {
this.component = component;
Expand All @@ -43,18 +40,14 @@ export abstract class BaseTooltipProcessor {
// 更新 this._cacheViewSpec
this._updateViewSpec(data, params);
const spec = this._cacheViewSpec;
if (isNil(spec?.[this.activeType]) || spec.visible === false) {
if (isNil(spec) || spec.visible === false) {
return TooltipResult.failed;
}
params.tooltipSpec = this.component.getSpec();
params.activeTooltipSpec = spec;

// 更新 this._cacheActualTooltip
this._updateActualTooltip(data, params);
params.tooltipActual = this._cacheActualTooltip;

// 判断 tooltip 是否为空
const { title, content } = this._cacheActualTooltip;
const { title, content } = spec;

const isEmpty = isNil(title?.key) && isNil(title?.value) && !content?.length;
// 触发事件
Expand Down Expand Up @@ -114,45 +107,6 @@ export abstract class BaseTooltipProcessor {
}
}

/**
* 合成 tooltip 内容
* @param data
* @param params
* @param changePositionOnly
*/
protected _updateActualTooltip(data: TooltipData, params: TooltipHandlerParams) {
const pattern = this._cacheViewSpec[this.activeType] ?? (params.tooltipSpec?.[this.activeType] as ITooltipPattern);
const { changePositionOnly } = params;

if (!changePositionOnly || !this._cacheActualTooltip) {
// 合成 tooltip 内容
const tooltipContent = getShowContent(pattern, data, params);

// 判断可见性
const visible = isValid(tooltipContent) ? getTooltipPatternValue(pattern.visible, data, params) !== false : false; // 最终展示数据为 null 则不展示

this._cacheActualTooltip = {
...tooltipContent,
visible,
activeType: pattern.activeType,
data
};
const updateTitle =
this._cacheViewSpec[this.activeType]?.updateTitle ?? params.tooltipSpec?.[this.activeType]?.updateTitle;

if (updateTitle) {
const prevTitle = this._cacheActualTooltip.title;
this._cacheActualTooltip.title = updateTitle(prevTitle, data, params) ?? prevTitle;
}
const updateContent =
this._cacheViewSpec[this.activeType]?.updateContent ?? params.tooltipSpec?.[this.activeType]?.updateContent;
if (updateContent) {
const prevContent = this._cacheActualTooltip.content;
this._cacheActualTooltip.content = updateContent?.(prevContent, data, params) ?? prevContent;
}
}
}

/** 判断是否应该触发 tooltip */
shouldHandleTooltip(params: BaseEventParams, info: TooltipInfo): boolean {
if (isNil(info)) {
Expand All @@ -164,6 +118,5 @@ export abstract class BaseTooltipProcessor {

clearCache() {
this._cacheViewSpec = undefined;
this._cacheActualTooltip = undefined;
}
}
104 changes: 85 additions & 19 deletions packages/vchart/src/component/tooltip/utils/common.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { isArray, isFunction, isNil, isValid } from '@visactor/vutils';
import { isArray, isFunction, isNil, isValid, TimeUtil } from '@visactor/vutils';
import type {
Datum,
ITooltipActual,
ITooltipLineActual,
ITooltipLinePattern,
ITooltipPattern,
MaybeArray,
TooltipActiveType,
TooltipContentProperty,
TooltipData,
TooltipPatternCallback,
TooltipPatternProperty
} from '../../../typings';
import type { ISeriesTooltipSpec, ITooltipActiveTypeAsKeys, ITooltipSpec, TooltipHandlerParams } from '../interface';
import type { BaseEventParams } from '../../../event/interface';
import { getTooltipContentValue } from './get-value';

export const getTooltipActualActiveType = (spec?: ITooltipSpec): TooltipActiveType[] => {
if (spec?.visible === false) {
Expand Down Expand Up @@ -54,61 +60,106 @@ export function isEmptyPos(params: BaseEventParams): boolean {
return isNil(params.mark) && isNil(params.model) && isNil(params.datum);
}

function addContentLine(result: ITooltipPattern[], contentSpec: MaybeArray<ITooltipLinePattern>) {
function addContentLine(
result: ITooltipLineActual[],
contentSpec: MaybeArray<ITooltipLinePattern>,
shapeAttrs: Record<string, TooltipContentProperty<any>>,
datum: Datum[],
params?: TooltipHandlerParams
) {
const addByDatum = (spec: ITooltipLinePattern) => {
if (spec) {
datum.forEach(d => {
const res: ITooltipLineActual = {};
const finalSpec: ITooltipLinePattern = { ...shapeAttrs, ...spec };

Object.keys(finalSpec).forEach(k => {
if (k === 'key') {
res.key = getTimeString(
getTooltipContentValue(finalSpec.key, d, params, finalSpec.keyFormatter),
finalSpec.keyTimeFormat,
finalSpec.keyTimeFormatMode
);
} else if (k === 'value') {
res.value = getTimeString(
getTooltipContentValue(finalSpec.value, d, params, finalSpec.valueFormatter),
finalSpec.valueTimeFormat,
finalSpec.valueTimeFormatMode
);
} else {
(res as any)[k] = getTooltipContentValue((finalSpec as any)[k], d, params);
}
});
result.push(res);
});
}
};

if (isArray(contentSpec)) {
contentSpec.forEach(spec => {
spec && result.push(spec as ITooltipLinePattern);
(contentSpec as ITooltipLinePattern[]).forEach(spec => {
addByDatum(spec);
});
} else if (contentSpec) {
result.push(contentSpec as ITooltipLinePattern);
} else {
addByDatum(contentSpec as ITooltipLinePattern);
}
}

function parseContentFunction(
result: ITooltipPattern[],
result: ITooltipLineActual[],
contentSpec: TooltipPatternProperty<MaybeArray<ITooltipLinePattern>>,
shapeAttrs: Record<string, TooltipContentProperty<any>>,
data?: TooltipData,
datum?: Datum[],
params?: TooltipHandlerParams
) {
if (isFunction(contentSpec)) {
const specs = contentSpec(data, params);
const specs = (contentSpec as TooltipPatternCallback<MaybeArray<ITooltipLinePattern>>)(data, params);

addContentLine(result, specs);
addContentLine(result, specs, shapeAttrs, datum, params);
} else if (contentSpec) {
addContentLine(result, contentSpec);
addContentLine(result, contentSpec as MaybeArray<ITooltipLinePattern>, shapeAttrs, datum, params);
}
}

export function parseContent(
contentSpec: MaybeArray<TooltipPatternProperty<MaybeArray<ITooltipLinePattern>>>,
shapeAttrs: Record<string, TooltipContentProperty<any>>,
data?: TooltipData,
datum?: Datum[],
params?: TooltipHandlerParams
) {
const contents: ITooltipLinePattern[] = [];
): ITooltipLineActual[] {
const contents: ITooltipLineActual[] = [];

if (isArray(contentSpec)) {
contentSpec.forEach(spec => {
parseContentFunction(contents, spec, data, params);
(contentSpec as TooltipPatternProperty<MaybeArray<ITooltipLinePattern>>[]).forEach(spec => {
parseContentFunction(contents, spec, shapeAttrs, data, datum, params);
});
} else if (isFunction(contentSpec)) {
parseContentFunction(contents, contentSpec, data, params);
parseContentFunction(
contents,
contentSpec as TooltipPatternCallback<MaybeArray<ITooltipLinePattern>>,
shapeAttrs,
data,
datum,
params
);
} else if (contentSpec) {
addContentLine(contents, contentSpec as MaybeArray<ITooltipLinePattern>);
addContentLine(contents, contentSpec as MaybeArray<ITooltipLinePattern>, shapeAttrs, datum, params);
}

return contents;
}

export function combinePattern(patternList: ITooltipPattern[]) {
export function combineContents(patternList: ITooltipActual[]) {
if (!patternList || !patternList.length) {
return null;
}

// 拼接默认 tooltip content
const defaultPatternContent: ITooltipLinePattern[] = [];
const defaultPatternContent: ITooltipLineActual[] = [];
patternList.forEach(({ content }) => {
if (content) {
(content as ITooltipLinePattern[]).forEach(c => {
(content as ITooltipLineActual[]).forEach(c => {
defaultPatternContent.push(c);
});
}
Expand All @@ -123,3 +174,18 @@ export function combinePattern(patternList: ITooltipPattern[]) {

return patternList[0];
}

export const getTimeString = (value: any, timeFormat?: string, timeFormatMode?: 'local' | 'utc') => {
if (!timeFormat && !timeFormatMode) {
if (typeof value !== 'object') {
return value?.toString();
}
return value;
}

const timeUtil = TimeUtil.getInstance();
timeFormat = timeFormat || '%Y%m%d';
timeFormatMode = timeFormatMode || 'local';
const timeFormatter = timeFormatMode === 'local' ? timeUtil.timeFormat : timeUtil.timeUTCFormat;
return timeFormatter(timeFormat, value);
};
Loading

0 comments on commit 44ba42f

Please sign in to comment.