setup.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import { ref, watch } from "vue";
  2. import { toDecimalFull } from '@/utils/number';
  3. import { getTheme, ThemeEnum } from '@/common/config/theme';
  4. import { deepMerge } from '@/utils/objHandle'
  5. import { EChartsOption } from 'echarts';
  6. import * as echarts from 'echarts';
  7. // 命名待优化
  8. type Colors = {
  9. backgroundColor: string, // 图表背景颜色
  10. axisPointerLabelColor: string,
  11. legendTextColor: string,
  12. xAxisLineColor: string
  13. yAxisLineColor: string,
  14. seriesMarkLabelColor: string,
  15. seriesMarkLineColor: string,
  16. upColor: string,
  17. downColor: string,
  18. seriesLineColor: string,
  19. seriesAreaGradients: echarts.LinearGradientObject,
  20. }
  21. // 图表数据
  22. export type ChartData = {
  23. datas: number[], // 历史数据
  24. times: string[], // 历史日期
  25. yestclose: number, // 昨日收盘价
  26. last: number, // 最新行情价
  27. lastTime: string, // 最新行情时间
  28. decimal: number, // 保留小数位
  29. min: number, // Y轴最低指标线
  30. max: number, // Y轴最高指标线
  31. ma5: (number | string)[], //均线数据
  32. }
  33. export function handleEchart() {
  34. const options = ref<EChartsOption>({});
  35. // 当前主题
  36. const theme = getTheme();
  37. // 图表数据
  38. const chartData = ref<ChartData>({
  39. datas: [],
  40. times: [],
  41. yestclose: 0,
  42. last: 0,
  43. lastTime: '',
  44. decimal: 0,
  45. min: 0,
  46. max: 0,
  47. ma5: []
  48. });
  49. // 计算涨跌幅百分比
  50. const calcRatio = (val: number) => {
  51. const result = (Number(val) - chartData.value.yestclose) / chartData.value.yestclose * 100;
  52. return toDecimalFull(result) + '%';
  53. }
  54. // 初始化图表配置
  55. const initOptions = () => {
  56. const { datas, times, yestclose, last, min, max, ma5, decimal } = chartData.value;
  57. const option: EChartsOption = {
  58. legend: {
  59. //图例控件,点击图例控制哪些系列不显示
  60. type: 'scroll',
  61. itemWidth: 14,
  62. itemHeight: 2,
  63. left: '5%',
  64. top: 0,
  65. textStyle: {
  66. fontSize: 12,
  67. },
  68. },
  69. // 悬浮框
  70. tooltip: {
  71. trigger: 'axis',
  72. axisPointer: {
  73. type: 'cross',
  74. },
  75. backgroundColor: 'rgba(255,255,255,.9)',
  76. borderWidth: 1,
  77. borderRadius: 3,
  78. textStyle: {
  79. color: '#4d535c',
  80. },
  81. // eslint-disable-next-line
  82. formatter: (params: any) => {
  83. const i = params[0].dataIndex;
  84. const result = `
  85. <div><span style="display: inline-block; width: 40px">当前价:</span><span style="display: inline-block; width: 100px; text-align: right">${datas[i]}</span></div>
  86. <div><span style="display: inline-block; width: 40px">均价:</span><span style="display: inline-block; width: 100px; text-align: right">${ma5[i]}</span></div>
  87. <div><span style="display: inline-block; width: 40px">涨幅:</span><span style="display: inline-block; width: 100px; text-align: right">${calcRatio(datas[i])}</span></div>`;
  88. return result;
  89. },
  90. },
  91. grid: {
  92. top: '8%',
  93. left: '8%',
  94. right: '8%',
  95. bottom: '8%',
  96. },
  97. xAxis: {
  98. type: 'category',
  99. // X轴时间线
  100. data: times,
  101. splitLine: {
  102. // 坐标分隔线
  103. show: true,
  104. },
  105. },
  106. yAxis: [
  107. // Y轴左侧标签
  108. {
  109. id: 'leftPrice',
  110. scale: true,
  111. min: min,
  112. max: max,
  113. axisLabel: {
  114. formatter: (val: number) => toDecimalFull(val, decimal),
  115. }
  116. },
  117. // Y轴右侧标签
  118. {
  119. id: 'rightRatio',
  120. scale: true,
  121. min: min,
  122. max: max,
  123. splitLine: {
  124. show: false,
  125. },
  126. axisLabel: {
  127. formatter: (val: number) => calcRatio(val),
  128. }
  129. },
  130. ],
  131. // series 中不指定 yAxisId 或 yAxisIndex 默认关联 yAxis 第一个配置,xAxis 配置同理
  132. series: [
  133. {
  134. name: '当前价',
  135. type: 'line',
  136. yAxisId: 'leftPrice',
  137. data: chartData.value.datas,
  138. smooth: true,
  139. symbol: 'circle', //中时有小圆点
  140. lineStyle: {
  141. opacity: 0.8,
  142. width: 1,
  143. },
  144. markLine: {
  145. // 标线两端图标
  146. symbol: 'none',
  147. // 标线标签样式
  148. data: [
  149. {
  150. // 最新价
  151. yAxis: last,
  152. },
  153. {
  154. // 昨结价
  155. yAxis: yestclose,
  156. lineStyle: {
  157. color: '#333',
  158. },
  159. label: {
  160. show: false,
  161. }
  162. },
  163. ],
  164. },
  165. },
  166. {
  167. type: 'line',
  168. yAxisId: 'rightRatio', // 关联Y轴右侧标签
  169. data: datas,
  170. symbol: 'none',
  171. lineStyle: {
  172. width: 0,
  173. },
  174. },
  175. {
  176. name: '均价',
  177. type: 'line',
  178. data: ma5,
  179. smooth: true,
  180. symbol: 'none',
  181. lineStyle: {
  182. width: 1,
  183. opacity: 0.8,
  184. },
  185. },
  186. ],
  187. };
  188. options.value = deepMerge(option, getColors(theme.value));
  189. };
  190. // 动态更新数据
  191. const updateOptions = () => {
  192. const { datas, last, yestclose, min, max } = chartData.value;
  193. if (datas.length) {
  194. options.value = {
  195. yAxis: [
  196. // Y轴左侧标签
  197. {
  198. id: 'leftPrice',
  199. min: min,
  200. max: max,
  201. },
  202. // Y轴右侧标签
  203. {
  204. id: 'rightRatio',
  205. min: min,
  206. max: max,
  207. },
  208. ],
  209. series: [
  210. {
  211. markLine: {
  212. data: [
  213. {
  214. // 最新价
  215. yAxis: last,
  216. },
  217. {
  218. // 昨结价
  219. yAxis: yestclose,
  220. lineStyle: {
  221. color: '#333',
  222. },
  223. label: {
  224. show: false,
  225. }
  226. },
  227. ],
  228. },
  229. },
  230. ],
  231. };
  232. }
  233. };
  234. // 设置图表样式
  235. const setColors = (colors: Colors): EChartsOption => {
  236. const { yestclose } = chartData.value;
  237. return {
  238. // 图表背景颜色
  239. backgroundColor: colors.backgroundColor,
  240. axisPointer: {
  241. label: {
  242. color: colors.axisPointerLabelColor,
  243. },
  244. },
  245. legend: {
  246. textStyle: {
  247. color: colors.legendTextColor,
  248. },
  249. },
  250. xAxis: {
  251. splitLine: {
  252. lineStyle: {
  253. // 坐标分隔线颜色
  254. color: colors.xAxisLineColor,
  255. },
  256. },
  257. },
  258. yAxis: [
  259. // Y轴左侧标签
  260. {
  261. id: 'leftPrice',
  262. axisLabel: {
  263. color: (val: any) => {
  264. if (val > yestclose) return colors.upColor;
  265. if (val < yestclose) return colors.downColor;
  266. return '#3C454B';
  267. },
  268. },
  269. splitLine: {
  270. lineStyle: {
  271. // 坐标分隔线颜色
  272. color: colors.yAxisLineColor,
  273. },
  274. },
  275. },
  276. // Y轴右侧标签
  277. {
  278. id: 'rightRatio',
  279. axisLabel: {
  280. color: (val: any) => {
  281. if (val > yestclose) return colors.upColor;
  282. if (val < yestclose) return colors.downColor;
  283. return '#3C454B';
  284. },
  285. },
  286. },
  287. ],
  288. series: [
  289. {
  290. lineStyle: {
  291. color: colors.seriesLineColor,
  292. },
  293. areaStyle: {
  294. color: colors.seriesAreaGradients,
  295. shadowColor: 'rgba(0, 0, 0, 0.1)',
  296. shadowBlur: 10,
  297. },
  298. markLine: {
  299. // 标线标签样式
  300. label: {
  301. color: colors.seriesMarkLabelColor,
  302. },
  303. // 标线样式
  304. lineStyle: {
  305. color: colors.seriesMarkLineColor,
  306. },
  307. },
  308. }
  309. ]
  310. }
  311. }
  312. // 获取图表样式配置
  313. const getColors = (theme: ThemeEnum) => {
  314. switch (theme) {
  315. case ThemeEnum.default:
  316. case ThemeEnum.dark:
  317. return setColors({
  318. backgroundColor: 'transparent',
  319. axisPointerLabelColor: '#fff',
  320. legendTextColor: '#0e99e2',
  321. xAxisLineColor: '#171B1D',
  322. yAxisLineColor: '#171B1D',
  323. seriesMarkLabelColor: '#3C454B',
  324. seriesMarkLineColor: '#33393D',
  325. upColor: '#FF2B2B',
  326. downColor: '#1FF195',
  327. seriesLineColor: '#39afe6',
  328. seriesAreaGradients: new echarts.graphic.LinearGradient(0, 0, 0, 1,
  329. [
  330. {
  331. offset: 0,
  332. color: 'rgba(0, 136, 212, 0.7)',
  333. },
  334. {
  335. offset: 0.8,
  336. color: 'rgba(0, 136, 212, 0.02)',
  337. },
  338. ],
  339. false
  340. ),
  341. });
  342. case ThemeEnum.light:
  343. return setColors({
  344. backgroundColor: 'transparent',
  345. axisPointerLabelColor: '#fff',
  346. legendTextColor: '#FC9618',
  347. xAxisLineColor: '#DAE5EC',
  348. yAxisLineColor: '#DAE5EC',
  349. seriesMarkLabelColor: '#666',
  350. seriesMarkLineColor: '#ACB8C0',
  351. upColor: '#FF2B2B',
  352. downColor: '#00A843',
  353. seriesLineColor: '#3864d7',
  354. seriesAreaGradients: new echarts.graphic.LinearGradient(0, 0, 0, 1,
  355. [
  356. {
  357. offset: 0,
  358. color: 'rgba(0, 136, 212, 0.3)',
  359. },
  360. {
  361. offset: 1,
  362. color: 'rgba(0, 136, 212, 0.3)',
  363. },
  364. ],
  365. false
  366. ),
  367. });
  368. }
  369. }
  370. watch(theme, (val) => {
  371. options.value = getColors(val);
  372. });
  373. return {
  374. chartData,
  375. options,
  376. initOptions,
  377. updateOptions,
  378. }
  379. }