| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- 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<EChartsOption>({});
- // 当前主题
- const theme = getTheme();
- // 图表数据
- const chartData = ref<ChartData>({
- 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 = `
- <div><span style="display: inline-block; width: 40px">当前价:</span><span style="display: inline-block; width: 100px; text-align: right">${datas[i]}</span></div>
- <div><span style="display: inline-block; width: 40px">均价:</span><span style="display: inline-block; width: 100px; text-align: right">${ma5[i]}</span></div>
- <div><span style="display: inline-block; width: 40px">涨幅:</span><span style="display: inline-block; width: 100px; text-align: right">${calcRatio(datas[i])}</span></div>`;
- 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,
- }
- }
|