import { ref, watch } from "vue"; import { toDecimalFull } from '@/utils/number'; import { getTheme, ThemeEnum } from '@/common/config/theme'; import { deepMerge } from '@/utils/objHandle' import { EChartsOption } from 'echarts'; import * as echarts from 'echarts'; // 命名待优化 type Colors = { backgroundColor: string, // 图表背景颜色 axisPointerLabelColor: string, legendTextColor: string, xAxisLineColor: string yAxisLineColor: string, seriesMarkLabelColor: string, seriesMarkLineColor: string, upColor: string, downColor: string, seriesLineColor: string, seriesAreaGradients: echarts.LinearGradientObject, } // 图表数据 export type ChartData = { datas: number[], // 历史数据 times: string[], // 历史日期 yestclose: number, // 昨日收盘价 last: number, // 最新行情价 lastTime: string, // 最新行情时间 decimal: number, // 保留小数位 min: number, // Y轴最低指标线 max: number, // Y轴最高指标线 ma5: (number | string)[], //均线数据 } export function handleEchart() { const options = ref({}); // 当前主题 const theme = getTheme(); // 图表数据 const chartData = ref({ datas: [], times: [], yestclose: 0, last: 0, lastTime: '', decimal: 0, min: 0, max: 0, ma5: [] }); // 计算涨跌幅百分比 const calcRatio = (val: number) => { const result = (Number(val) - chartData.value.yestclose) / chartData.value.yestclose * 100; return toDecimalFull(result) + '%'; } // 初始化图表配置 const initOptions = () => { const { datas, times, yestclose, last, min, max, ma5, decimal } = chartData.value; const option: EChartsOption = { legend: { //图例控件,点击图例控制哪些系列不显示 type: 'scroll', itemWidth: 14, itemHeight: 2, left: '5%', top: 0, textStyle: { fontSize: 12, }, }, // 悬浮框 tooltip: { trigger: 'axis', axisPointer: { type: 'cross', }, backgroundColor: 'rgba(255,255,255,.9)', borderWidth: 1, borderRadius: 3, textStyle: { color: '#4d535c', }, // eslint-disable-next-line formatter: (params: any) => { const i = params[0].dataIndex; const result = `
当前价:${datas[i]}
均价:${ma5[i]}
涨幅:${calcRatio(datas[i])}
`; return result; }, }, grid: { top: '8%', left: '8%', right: '8%', bottom: '8%', }, xAxis: { type: 'category', // X轴时间线 data: times, splitLine: { // 坐标分隔线 show: true, }, }, yAxis: [ // Y轴左侧标签 { id: 'leftPrice', scale: true, min: min, max: max, axisLabel: { formatter: (val: number) => toDecimalFull(val, decimal), } }, // Y轴右侧标签 { id: 'rightRatio', scale: true, min: min, max: max, splitLine: { show: false, }, axisLabel: { formatter: (val: number) => calcRatio(val), } }, ], // series 中不指定 yAxisId 或 yAxisIndex 默认关联 yAxis 第一个配置,xAxis 配置同理 series: [ { name: '当前价', type: 'line', yAxisId: 'leftPrice', data: chartData.value.datas, smooth: true, symbol: 'circle', //中时有小圆点 lineStyle: { opacity: 0.8, width: 1, }, markLine: { // 标线两端图标 symbol: 'none', // 标线标签样式 data: [ { // 最新价 yAxis: last, }, { // 昨结价 yAxis: yestclose, lineStyle: { color: '#333', }, label: { show: false, } }, ], }, }, { type: 'line', yAxisId: 'rightRatio', // 关联Y轴右侧标签 data: datas, symbol: 'none', lineStyle: { width: 0, }, }, { name: '均价', type: 'line', data: ma5, smooth: true, symbol: 'none', lineStyle: { width: 1, opacity: 0.8, }, }, ], }; options.value = deepMerge(option, getColors(theme.value)); }; // 动态更新数据 const updateOptions = () => { const { datas, last, yestclose, min, max } = chartData.value; if (datas.length) { options.value = { yAxis: [ // Y轴左侧标签 { id: 'leftPrice', min: min, max: max, }, // Y轴右侧标签 { id: 'rightRatio', min: min, max: max, }, ], series: [ { markLine: { data: [ { // 最新价 yAxis: last, }, { // 昨结价 yAxis: yestclose, lineStyle: { color: '#333', }, label: { show: false, } }, ], }, }, ], }; } }; // 设置图表样式 const setColors = (colors: Colors): EChartsOption => { const { yestclose } = chartData.value; return { // 图表背景颜色 backgroundColor: colors.backgroundColor, axisPointer: { label: { color: colors.axisPointerLabelColor, }, }, legend: { textStyle: { color: colors.legendTextColor, }, }, xAxis: { splitLine: { lineStyle: { // 坐标分隔线颜色 color: colors.xAxisLineColor, }, }, }, yAxis: [ // Y轴左侧标签 { id: 'leftPrice', axisLabel: { color: (val: any) => { if (val > yestclose) return colors.upColor; if (val < yestclose) return colors.downColor; return '#3C454B'; }, }, splitLine: { lineStyle: { // 坐标分隔线颜色 color: colors.yAxisLineColor, }, }, }, // Y轴右侧标签 { id: 'rightRatio', axisLabel: { color: (val: any) => { if (val > yestclose) return colors.upColor; if (val < yestclose) return colors.downColor; return '#3C454B'; }, }, }, ], series: [ { lineStyle: { color: colors.seriesLineColor, }, areaStyle: { color: colors.seriesAreaGradients, shadowColor: 'rgba(0, 0, 0, 0.1)', shadowBlur: 10, }, markLine: { // 标线标签样式 label: { color: colors.seriesMarkLabelColor, }, // 标线样式 lineStyle: { color: colors.seriesMarkLineColor, }, }, } ] } } // 获取图表样式配置 const getColors = (theme: ThemeEnum) => { switch (theme) { case ThemeEnum.default: case ThemeEnum.dark: return setColors({ backgroundColor: 'transparent', axisPointerLabelColor: '#fff', legendTextColor: '#0e99e2', xAxisLineColor: '#171B1D', yAxisLineColor: '#171B1D', seriesMarkLabelColor: '#3C454B', seriesMarkLineColor: '#33393D', upColor: '#FF2B2B', downColor: '#1FF195', seriesLineColor: '#39afe6', seriesAreaGradients: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(0, 136, 212, 0.7)', }, { offset: 0.8, color: 'rgba(0, 136, 212, 0.02)', }, ], false ), }); case ThemeEnum.light: return setColors({ backgroundColor: 'transparent', axisPointerLabelColor: '#fff', legendTextColor: '#FC9618', xAxisLineColor: '#DAE5EC', yAxisLineColor: '#DAE5EC', seriesMarkLabelColor: '#666', seriesMarkLineColor: '#ACB8C0', upColor: '#FF2B2B', downColor: '#00A843', seriesLineColor: '#3864d7', seriesAreaGradients: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(0, 136, 212, 0.3)', }, { offset: 1, color: 'rgba(0, 136, 212, 0.3)', }, ], false ), }); } } watch(theme, (val) => { options.value = getColors(val); }); return { chartData, options, initOptions, updateOptions, } }