/** * 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(null); const [markerId, setMarkerId] = useState(null); const [highlightId, setHighlightId] = useState(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, }; };