266 lines
6.0 KiB
TypeScript
266 lines
6.0 KiB
TypeScript
/**
|
||
* 图表通用工具函数
|
||
*
|
||
* 包含图表初始化、技术指标管理等通用逻辑
|
||
*/
|
||
|
||
import type { Chart, ActionType } from 'klinecharts';
|
||
|
||
/**
|
||
* 安全地执行图表操作(捕获异常)
|
||
*
|
||
* @param operation 操作名称
|
||
* @param fn 执行函数
|
||
* @returns T | null 执行结果或 null
|
||
*/
|
||
export const safeChartOperation = <T>(
|
||
operation: string,
|
||
fn: () => T
|
||
): T | null => {
|
||
try {
|
||
return fn();
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 创建技术指标
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param indicatorName 指标名称(如 'MA', 'MACD', 'VOL')
|
||
* @param params 指标参数(可选)
|
||
* @param isStack 是否叠加(主图指标为 true,副图为 false)
|
||
* @returns string | null 指标 ID
|
||
*/
|
||
export const createIndicator = (
|
||
chart: Chart,
|
||
indicatorName: string,
|
||
params?: number[],
|
||
isStack: boolean = false
|
||
): string | null => {
|
||
return safeChartOperation(`createIndicator:${indicatorName}`, () => {
|
||
const indicatorId = chart.createIndicator(
|
||
{
|
||
name: indicatorName,
|
||
...(params && { calcParams: params }),
|
||
},
|
||
isStack
|
||
);
|
||
|
||
return indicatorId;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 移除技术指标
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param indicatorId 指标 ID(不传则移除所有指标)
|
||
*/
|
||
export const removeIndicator = (chart: Chart, indicatorId?: string): void => {
|
||
safeChartOperation('removeIndicator', () => {
|
||
if (indicatorId) {
|
||
chart.removeIndicator({ id: indicatorId });
|
||
} else {
|
||
chart.removeIndicator({});
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 批量创建副图指标
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param indicators 指标名称数组
|
||
* @returns string[] 指标 ID 数组
|
||
*/
|
||
export const createSubIndicators = (
|
||
chart: Chart,
|
||
indicators: string[]
|
||
): string[] => {
|
||
const ids: string[] = [];
|
||
|
||
indicators.forEach((name) => {
|
||
const id = createIndicator(chart, name, undefined, false);
|
||
if (id) {
|
||
ids.push(id);
|
||
}
|
||
});
|
||
|
||
return ids;
|
||
};
|
||
|
||
/**
|
||
* 设置图表缩放级别
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param zoom 缩放级别(0.5 - 2.0)
|
||
*/
|
||
export const setChartZoom = (chart: Chart, zoom: number): void => {
|
||
safeChartOperation('setChartZoom', () => {
|
||
// KLineChart 10.0: 使用 setBarSpace 方法调整 K 线宽度(实现缩放效果)
|
||
const baseBarSpace = 8; // 默认 K 线宽度(px)
|
||
const newBarSpace = Math.max(4, Math.min(16, baseBarSpace * zoom));
|
||
|
||
// 注意:KLineChart 10.0 可能没有直接的 zoom API,需要通过调整样式实现
|
||
chart.setStyles({
|
||
candle: {
|
||
bar: {
|
||
upBorderColor: undefined, // 保持默认
|
||
upColor: undefined,
|
||
downBorderColor: undefined,
|
||
downColor: undefined,
|
||
},
|
||
// 通过调整蜡烛图宽度实现缩放效果
|
||
tooltip: {
|
||
showRule: 'always',
|
||
},
|
||
},
|
||
});
|
||
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 滚动到指定时间
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param timestamp 目标时间戳
|
||
*/
|
||
export const scrollToTimestamp = (chart: Chart, timestamp: number): void => {
|
||
safeChartOperation('scrollToTimestamp', () => {
|
||
// KLineChart 10.0: 使用 scrollToTimestamp 方法
|
||
chart.scrollToTimestamp(timestamp);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 调整图表大小(响应式)
|
||
*
|
||
* @param chart KLineChart 实例
|
||
*/
|
||
export const resizeChart = (chart: Chart): void => {
|
||
safeChartOperation('resizeChart', () => {
|
||
chart.resize();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 获取图表可见数据范围
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @returns { from: number, to: number } | null 可见范围
|
||
*/
|
||
export const getVisibleRange = (chart: Chart): { from: number; to: number } | null => {
|
||
return safeChartOperation('getVisibleRange', () => {
|
||
const data = chart.getDataList();
|
||
if (!data || data.length === 0) {
|
||
return null;
|
||
}
|
||
|
||
// 简化实现:返回所有数据范围
|
||
// 实际项目中可通过 chart 的内部状态获取可见范围
|
||
return {
|
||
from: 0,
|
||
to: data.length - 1,
|
||
};
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 清空图表数据
|
||
*
|
||
* @param chart KLineChart 实例
|
||
*/
|
||
export const clearChartData = (chart: Chart): void => {
|
||
safeChartOperation('clearChartData', () => {
|
||
chart.resetData();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 截图(导出图表为图片)
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param includeOverlay 是否包含 overlay
|
||
* @returns string | null Base64 图片数据
|
||
*/
|
||
export const exportChartImage = (
|
||
chart: Chart,
|
||
includeOverlay: boolean = true
|
||
): string | null => {
|
||
return safeChartOperation('exportChartImage', () => {
|
||
// KLineChart 10.0: 使用 getConvertPictureUrl 方法
|
||
const imageData = chart.getConvertPictureUrl(includeOverlay, 'png', '#ffffff');
|
||
|
||
return imageData;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 切换十字光标显示
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param show 是否显示
|
||
*/
|
||
export const toggleCrosshair = (chart: Chart, show: boolean): void => {
|
||
safeChartOperation('toggleCrosshair', () => {
|
||
chart.setStyles({
|
||
crosshair: {
|
||
show,
|
||
},
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 切换网格显示
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param show 是否显示
|
||
*/
|
||
export const toggleGrid = (chart: Chart, show: boolean): void => {
|
||
safeChartOperation('toggleGrid', () => {
|
||
chart.setStyles({
|
||
grid: {
|
||
show,
|
||
},
|
||
});
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 订阅图表事件
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param eventName 事件名称
|
||
* @param handler 事件处理函数
|
||
*/
|
||
export const subscribeChartEvent = (
|
||
chart: Chart,
|
||
eventName: ActionType,
|
||
handler: (...args: any[]) => void
|
||
): void => {
|
||
safeChartOperation(`subscribeChartEvent:${eventName}`, () => {
|
||
chart.subscribeAction(eventName, handler);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 取消订阅图表事件
|
||
*
|
||
* @param chart KLineChart 实例
|
||
* @param eventName 事件名称
|
||
* @param handler 事件处理函数
|
||
*/
|
||
export const unsubscribeChartEvent = (
|
||
chart: Chart,
|
||
eventName: ActionType,
|
||
handler: (...args: any[]) => void
|
||
): void => {
|
||
safeChartOperation(`unsubscribeChartEvent:${eventName}`, () => {
|
||
chart.unsubscribeAction(eventName, handler);
|
||
});
|
||
};
|