Files
vf_react/src/components/StockChart/config/klineTheme.ts
2025-11-24 14:08:41 +08:00

459 lines
11 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.

/**
* KLineChart 主题配置
*
* 适配 klinecharts@10.0.0-beta1
* 参考: https://github.com/klinecharts/KLineChart/blob/main/docs/en-US/guide/styles.md
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
// ⚠️ 使用 any 类型绕过 KLineChart 类型定义的限制beta 版本类型不完整)
import type { DeepPartial, Styles } from 'klinecharts';
/**
* 图表主题颜色配置
*/
export const CHART_COLORS = {
// 涨跌颜色(中国市场习惯:红涨绿跌)
up: '#ef5350', // 上涨红色
down: '#26a69a', // 下跌绿色
neutral: '#888888', // 平盘灰色
// 主题色(继承自 Argon Dashboard
primary: '#1b3bbb', // Navy 500
secondary: '#728fea', // Navy 300
background: '#ffffff',
backgroundDark: '#1B254B',
// 文本颜色
text: '#333333',
textSecondary: '#888888',
textDark: '#ffffff',
// 网格颜色
grid: '#e0e0e0',
gridDark: '#2d3748',
// 边框颜色
border: '#e0e0e0',
borderDark: '#2d3748',
// 事件标记颜色
eventMarker: '#ff9800',
eventMarkerText: '#ffffff',
};
/**
* 浅色主题配置(默认)
*/
export const lightTheme: any = {
candle: {
type: 'candle_solid', // 实心蜡烛图
bar: {
upColor: CHART_COLORS.up,
downColor: CHART_COLORS.down,
noChangeColor: CHART_COLORS.neutral,
},
priceMark: {
show: true,
high: {
color: CHART_COLORS.up,
},
low: {
color: CHART_COLORS.down,
},
},
tooltip: {
showRule: 'always',
showType: 'standard',
// labels: ['时间: ', '开: ', '收: ', '高: ', '低: ', '成交量: '], // ❌ KLineChart 类型不支持自定义 labels
text: {
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
color: CHART_COLORS.text,
},
},
},
indicator: {
tooltip: {
showRule: 'always',
showType: 'standard',
text: {
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
color: CHART_COLORS.text,
},
},
},
xAxis: {
axisLine: {
show: true,
color: CHART_COLORS.border,
},
tickLine: {
show: true,
length: 3,
color: CHART_COLORS.border,
},
tickText: {
show: true,
color: CHART_COLORS.textSecondary,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
size: 12,
},
},
yAxis: {
axisLine: {
show: true,
color: CHART_COLORS.border,
},
tickLine: {
show: true,
length: 3,
color: CHART_COLORS.border,
},
tickText: {
show: true,
color: CHART_COLORS.textSecondary,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
size: 12,
},
type: 'normal', // 'normal' | 'percentage' | 'log'
},
grid: {
show: true,
horizontal: {
show: true,
size: 1,
color: CHART_COLORS.grid,
style: 'dashed',
},
vertical: {
show: false, // 垂直网格线通常关闭,避免过于密集
},
},
separator: {
size: 1,
color: CHART_COLORS.border,
},
crosshair: {
show: true,
horizontal: {
show: true,
line: {
show: true,
style: 'dashed',
dashedValue: [4, 2], // ✅ 修复: 使用 dashedValue 而非 dashValue
size: 1,
color: CHART_COLORS.primary,
},
text: {
show: true,
color: CHART_COLORS.textDark,
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
backgroundColor: CHART_COLORS.primary,
},
},
vertical: {
show: true,
line: {
show: true,
style: 'dashed',
dashedValue: [4, 2], // ✅ 修复: 使用 dashedValue 而非 dashValue
size: 1,
color: CHART_COLORS.primary,
},
text: {
show: true,
color: CHART_COLORS.textDark,
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
backgroundColor: CHART_COLORS.primary,
},
},
},
overlay: {
// 事件标记覆盖层样式
point: {
color: CHART_COLORS.eventMarker,
borderColor: CHART_COLORS.eventMarker,
borderSize: 1,
radius: 5,
activeColor: CHART_COLORS.eventMarker,
activeBorderColor: CHART_COLORS.eventMarker,
activeBorderSize: 2,
activeRadius: 6,
},
line: {
style: 'solid',
smooth: false,
color: CHART_COLORS.eventMarker,
size: 1,
dashedValue: [2, 2],
},
text: {
style: 'fill',
color: CHART_COLORS.eventMarkerText,
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
offset: [0, 0],
},
rect: {
style: 'fill',
color: CHART_COLORS.eventMarker,
borderColor: CHART_COLORS.eventMarker,
borderSize: 1,
borderRadius: 4,
borderStyle: 'solid',
borderDashedValue: [2, 2],
},
},
};
/**
* 深色主题配置
*/
export const darkTheme: any = {
...lightTheme,
candle: {
...lightTheme.candle,
tooltip: {
...lightTheme.candle?.tooltip,
text: {
...lightTheme.candle?.tooltip?.text,
color: CHART_COLORS.textDark,
},
},
},
indicator: {
...lightTheme.indicator,
tooltip: {
...lightTheme.indicator?.tooltip,
text: {
...lightTheme.indicator?.tooltip?.text,
color: CHART_COLORS.textDark,
},
},
},
xAxis: {
...lightTheme.xAxis,
axisLine: {
show: true,
color: CHART_COLORS.borderDark,
},
tickLine: {
show: true,
length: 3,
color: CHART_COLORS.borderDark,
},
tickText: {
...lightTheme.xAxis?.tickText,
color: CHART_COLORS.textDark,
},
},
yAxis: {
...lightTheme.yAxis,
axisLine: {
show: true,
color: CHART_COLORS.borderDark,
},
tickLine: {
show: true,
length: 3,
color: CHART_COLORS.borderDark,
},
tickText: {
...lightTheme.yAxis?.tickText,
color: CHART_COLORS.textDark,
},
},
grid: {
show: true,
horizontal: {
show: true,
size: 1,
color: CHART_COLORS.gridDark,
style: 'dashed',
},
vertical: {
show: false,
},
},
separator: {
size: 1,
color: CHART_COLORS.borderDark,
},
};
/**
* 分时图专用主题配置
* 特点面积图样式、均价线、百分比Y轴
*/
export const timelineTheme: any = {
...lightTheme,
candle: {
type: 'area', // ✅ 面积图模式(分时线)
area: {
lineSize: 2,
lineColor: CHART_COLORS.up, // 默认红色,实际会根据涨跌动态调整
value: 'close',
backgroundColor: [
{
offset: 0,
color: 'rgba(239, 83, 80, 0.2)', // 红色半透明渐变(顶部)
},
{
offset: 1,
color: 'rgba(239, 83, 80, 0.01)', // 红色几乎透明(底部)
},
],
},
priceMark: {
show: true,
high: {
show: false, // 分时图不显示最高最低价标记
},
low: {
show: false,
},
last: {
show: true,
upColor: CHART_COLORS.up,
downColor: CHART_COLORS.down,
noChangeColor: CHART_COLORS.neutral,
line: {
show: true,
style: 'dashed',
dashedValue: [4, 2], // ✅ 修复: 使用 dashedValue 而非 dashValue
size: 1,
},
text: {
show: true,
size: 12,
paddingLeft: 4,
paddingTop: 2,
paddingRight: 4,
paddingBottom: 2,
borderRadius: 2,
},
},
},
tooltip: {
showRule: 'always',
showType: 'standard',
// ❌ KLineChart 类型不支持自定义 labels 和 formatter需要在运行时通过 API 设置)
// labels: ['时间: ', '现价: ', '涨跌: ', '均价: ', '昨收: ', '成交量: '],
// formatter: (data: any, indicator: any) => { ... },
text: {
size: 12,
family: 'Helvetica, Arial, sans-serif',
weight: 'normal',
color: CHART_COLORS.text,
},
},
},
yAxis: {
...lightTheme.yAxis,
type: 'percentage', // ✅ 百分比模式
position: 'left', // Y轴在左侧
inside: false,
reverse: false,
tickText: {
...lightTheme.yAxis?.tickText,
// ❌ KLineChart 类型不支持自定义 formatter需要在运行时通过 API 设置)
// formatter: (value: any) => {
// const percent = (value * 100).toFixed(2);
// if (Math.abs(value) < 0.0001) return '0.00%';
// return value > 0 ? `+${percent}%` : `${percent}%`;
// },
},
},
grid: {
show: true,
horizontal: {
show: true,
size: 1,
color: CHART_COLORS.grid,
style: 'solid', // 分时图使用实线网格
},
vertical: {
show: false,
},
},
};
/**
* 分时图深色主题
*/
export const timelineThemeDark: any = {
...timelineTheme,
...darkTheme,
candle: {
...timelineTheme.candle,
tooltip: {
...timelineTheme.candle?.tooltip,
text: {
...timelineTheme.candle?.tooltip?.text,
color: CHART_COLORS.textDark,
},
},
},
grid: {
...timelineTheme.grid,
horizontal: {
...timelineTheme.grid?.horizontal,
color: CHART_COLORS.gridDark,
},
},
};
/**
* 获取主题配置(根据 Chakra UI colorMode
*/
export const getTheme = (colorMode: 'light' | 'dark' = 'light'): any => {
return colorMode === 'dark' ? darkTheme : lightTheme;
};
/**
* 获取分时图主题配置
*/
export const getTimelineTheme = (colorMode: 'light' | 'dark' = 'light'): any => {
const baseTheme = colorMode === 'dark' ? timelineThemeDark : timelineTheme;
// ✅ 添加成交量指标样式(蓝色渐变柱状图)+ 成交量单位格式化
return {
...baseTheme,
indicator: {
...baseTheme.indicator,
bars: [
{
upColor: 'rgba(59, 130, 246, 0.6)', // 蓝色(涨)
downColor: 'rgba(59, 130, 246, 0.6)', // 蓝色(跌)- 分时图成交量统一蓝色
noChangeColor: 'rgba(59, 130, 246, 0.6)',
}
],
// ❌ KLineChart 类型不支持自定义 formatter需要在运行时通过 API 设置)
tooltip: {
...baseTheme.indicator?.tooltip,
// formatter: (params: any) => {
// if (params.name === 'VOL' && params.calcParamsText) {
// const volume = params.calcParamsText.match(/\d+/)?.[0];
// if (volume) {
// const hands = Math.floor(Number(volume) / 100);
// return `成交量: ${hands.toLocaleString()}手`;
// }
// }
// return params.calcParamsText || '';
// },
},
},
};
};