Files
vf_react/src/components/StockChart/hooks/useEventMarker.ts
2025-11-26 09:44:21 +08:00

201 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* useEventMarker Hook
*
* 管理事件标记的创建、更新和删除
*/
import { useEffect, useState, useCallback } from 'react';
import type { Chart } from 'klinecharts';
import type { EventMarker, KLineDataPoint } from '../types';
import {
createEventMarkerFromTime,
createEventMarkerOverlay,
createEventHighlightOverlay,
removeAllEventMarkers,
} from '../utils/eventMarkerUtils';
export interface UseEventMarkerOptions {
/** KLineChart 实例 */
chart: Chart | null;
/** K 线数据(用于定位标记) */
data: KLineDataPoint[];
/** 事件时间ISO 字符串) */
eventTime?: string;
/** 事件标题(用于标记标签) */
eventTitle?: string;
/** 是否自动创建标记 */
autoCreate?: boolean;
}
export interface UseEventMarkerReturn {
/** 当前标记 */
marker: EventMarker | null;
/** 标记 ID已添加到图表 */
markerId: string | null;
/** 创建标记 */
createMarker: (time: string, label: string, color?: string) => void;
/** 移除标记 */
removeMarker: () => void;
/** 移除所有标记 */
removeAllMarkers: () => void;
}
/**
* 事件标记管理 Hook
*
* @param options 配置选项
* @returns UseEventMarkerReturn
*
* @example
* const { marker, createMarker, removeMarker } = useEventMarker({
* chart,
* data,
* eventTime: '2024-01-01 10:00:00',
* eventTitle: '重大公告',
* autoCreate: true,
* });
*/
export const useEventMarker = (
options: UseEventMarkerOptions
): UseEventMarkerReturn => {
const {
chart,
data,
eventTime,
eventTitle = '事件发生',
autoCreate = true,
} = options;
const [marker, setMarker] = useState<EventMarker | null>(null);
const [markerId, setMarkerId] = useState<string | null>(null);
const [highlightId, setHighlightId] = useState<string | null>(null);
/**
* 创建事件标记
*/
const createMarker = useCallback(
(time: string, label: string, color?: string) => {
if (!chart || !data || data.length === 0) {
return;
}
try {
// 1. 创建事件标记配置
const eventMarker = createEventMarkerFromTime(time, label, color);
setMarker(eventMarker);
// 2. 创建 Overlay
const overlay = createEventMarkerOverlay(eventMarker, data);
if (!overlay) {
return;
}
// 3. 添加到图表
const id = chart.createOverlay(overlay);
if (!id || (Array.isArray(id) && id.length === 0)) {
return;
}
const actualId = Array.isArray(id) ? id[0] : id;
setMarkerId(actualId as string);
// 4. 创建黄色高亮背景(事件影响日)
const highlightOverlay = createEventHighlightOverlay(time, data);
if (highlightOverlay) {
const highlightResult = chart.createOverlay(highlightOverlay);
const actualHighlightId = Array.isArray(highlightResult) ? highlightResult[0] : highlightResult;
setHighlightId(actualHighlightId as string);
}
} catch (err) {
// 忽略创建标记时的错误
}
},
[chart, data]
);
/**
* 移除事件标记
*/
const removeMarker = useCallback(() => {
if (!chart) {
return;
}
try {
if (markerId) {
chart.removeOverlay({ id: markerId });
}
if (highlightId) {
chart.removeOverlay({ id: highlightId });
}
setMarker(null);
setMarkerId(null);
setHighlightId(null);
} catch (err) {
// 忽略移除标记时的错误
}
}, [chart, markerId, highlightId]);
/**
* 移除所有标记
*/
const removeAllMarkers = useCallback(() => {
if (!chart) {
return;
}
try {
removeAllEventMarkers(chart);
setMarker(null);
setMarkerId(null);
setHighlightId(null);
} catch (err) {
// 忽略移除所有标记时的错误
}
}, [chart]);
// 自动创建标记(当 eventTime 和数据都准备好时)
useEffect(() => {
if (
autoCreate &&
eventTime &&
chart &&
data &&
data.length > 0 &&
!markerId // 避免重复创建
) {
createMarker(eventTime, eventTitle);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [eventTime, chart, data, autoCreate]);
// 清理:组件卸载时移除所有标记
useEffect(() => {
return () => {
if (chart) {
try {
if (markerId) {
chart.removeOverlay({ id: markerId });
}
if (highlightId) {
chart.removeOverlay({ id: highlightId });
}
} catch (err) {
// 忽略清理时的错误
}
}
};
}, [chart, markerId, highlightId]);
return {
marker,
markerId,
createMarker,
removeMarker,
removeAllMarkers,
};
};