options.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. import { reactive, watch } from 'vue'
  2. import { ECOption } from '@/components/base/echarts/core'
  3. import { timerInterceptor } from '@/utils/timer'
  4. import { ChartCycleType } from '@/constants/chart'
  5. import { useGlobalStore } from '@/stores'
  6. import { EchartsDataset, EchartsOptions, Colors } from './types'
  7. import moment from 'moment'
  8. const globalStore = useGlobalStore()
  9. const { appTheme } = globalStore.$toRefs()
  10. function getColors() {
  11. // 默认主题色配置
  12. const defaultColors: Colors = {
  13. upColor: '#ff3333',
  14. downColor: '#0aab62',
  15. xAxisLineColor: 'rgba(128,128,128,.1)',
  16. yAxisLineColor: 'rgba(128,128,128,.1)',
  17. }
  18. const colors = {
  19. default: defaultColors,
  20. dark: defaultColors,
  21. light: {
  22. ...defaultColors,
  23. xAxisLineColor: '#dae5ec',
  24. yAxisLineColor: '#dae5ec',
  25. }
  26. }
  27. return colors[appTheme.value];
  28. }
  29. export function useOptions(dataset: EchartsDataset) {
  30. // 图表配置项
  31. const options = reactive<EchartsOptions>({
  32. cycleType: ChartCycleType.Minutes,
  33. colors: getColors(),
  34. candlestick: {},
  35. macd: {},
  36. vol: {},
  37. kdj: {},
  38. cci: {},
  39. })
  40. const getDefaultOption = (): ECOption => {
  41. const { source } = dataset.candlestick;
  42. const { xAxisLineColor } = options.colors;
  43. return {
  44. grid: {
  45. left: '10px',
  46. right: '10px',
  47. top: '15px',
  48. bottom: '10px',
  49. containLabel: true,
  50. },
  51. dataZoom: {
  52. type: 'inside',
  53. startValue: source.length - 60, // 起始显示K线条数(最新60条)
  54. endValue: source.length,
  55. minValueSpan: 30, // 限制窗口缩放显示最少数据条数
  56. maxValueSpan: 200, // 限制窗口缩放显示最大数据条数
  57. },
  58. axisPointer: {
  59. label: {
  60. backgroundColor: 'rgba(128,128,128,.75)'
  61. }
  62. },
  63. xAxis: {
  64. type: 'category',
  65. axisLabel: {
  66. formatter: (val: string) => {
  67. switch (options.cycleType) {
  68. case ChartCycleType.Day: {
  69. return moment(val).format('YYYY-MM-DD')
  70. }
  71. default: {
  72. return moment(val).format('HH:mm')
  73. }
  74. }
  75. },
  76. margin: 12,
  77. },
  78. axisPointer: {
  79. label: {
  80. formatter: (params) => {
  81. switch (options.cycleType) {
  82. case ChartCycleType.Day: {
  83. return moment(params.value).format('YYYY-MM-DD')
  84. }
  85. case ChartCycleType.Hours2:
  86. case ChartCycleType.Hours4: {
  87. return moment(params.value).format('YYYY-MM-DD HH:00:00')
  88. }
  89. default: {
  90. return moment(params.value).format('YYYY-MM-DD HH:mm:00')
  91. }
  92. }
  93. },
  94. }
  95. },
  96. axisTick: {
  97. show: false,
  98. }
  99. },
  100. yAxis: {
  101. scale: true,
  102. splitLine: {
  103. lineStyle: {
  104. // 坐标分隔线颜色
  105. color: xAxisLineColor,
  106. },
  107. },
  108. },
  109. }
  110. }
  111. // K线配置项
  112. const setCandlestickOption = () => {
  113. const { dimensions, source } = dataset.candlestick;
  114. const { upColor, downColor } = options.colors;
  115. options.candlestick = {
  116. ...getDefaultOption(),
  117. dataset: {
  118. dimensions,
  119. source,
  120. },
  121. series: [
  122. {
  123. name: 'K线',
  124. type: 'candlestick',
  125. itemStyle: {
  126. color: upColor,
  127. color0: downColor,
  128. borderColor: upColor,
  129. borderColor0: downColor,
  130. },
  131. // 最新价标线
  132. markLine: {
  133. symbolSize: 6,
  134. // 标线标签样式
  135. label: {
  136. color: '#fff',
  137. backgroundColor: 'rgba(128,128,128,.75)',
  138. padding: 5,
  139. borderRadius: 3,
  140. position: 'insideStartTop',
  141. },
  142. // 标线样式
  143. lineStyle: {
  144. type: 'dashed',
  145. color: 'rgba(102,102,102,.6)'
  146. },
  147. data: [
  148. {
  149. // 收盘价
  150. yAxis: source.length ? source[source.length - 1].close : 0,
  151. },
  152. ],
  153. },
  154. },
  155. {
  156. name: 'MA5',
  157. type: 'line',
  158. sampling: 'average', //折线图在数据量远大于像素点时候的降采样策略,开启后可以有效的优化图表的绘制效率
  159. smooth: true,
  160. symbol: 'none',
  161. lineStyle: {
  162. width: 1,
  163. opacity: 0.8,
  164. },
  165. },
  166. {
  167. name: 'MA10',
  168. type: 'line',
  169. sampling: 'average',
  170. smooth: true,
  171. symbol: 'none',
  172. lineStyle: {
  173. width: 1,
  174. opacity: 0.8,
  175. },
  176. },
  177. {
  178. name: 'MA15',
  179. type: 'line',
  180. sampling: 'average',
  181. smooth: true,
  182. symbol: 'none',
  183. lineStyle: {
  184. width: 1,
  185. opacity: 0.8,
  186. },
  187. },
  188. ],
  189. }
  190. }
  191. // MACD配置项
  192. const setMacdOption = () => {
  193. const { upColor, downColor } = options.colors;
  194. const { dimensions, source } = dataset.macd;
  195. options.macd = {
  196. ...getDefaultOption(),
  197. dataset: {
  198. dimensions,
  199. source,
  200. },
  201. series: [
  202. {
  203. name: 'MACD',
  204. type: 'bar',
  205. sampling: 'average',
  206. barWidth: '20%',
  207. itemStyle: {
  208. color: ({ data }) => {
  209. const { macd } = data as { macd: number };
  210. if (macd > 0) {
  211. return upColor;
  212. } else {
  213. return downColor;
  214. }
  215. },
  216. }
  217. },
  218. {
  219. name: 'DIF',
  220. type: 'line',
  221. sampling: 'average',
  222. smooth: true,
  223. symbol: 'none',
  224. lineStyle: {
  225. width: 1,
  226. opacity: 0.8,
  227. },
  228. },
  229. {
  230. name: 'DEA',
  231. type: 'line',
  232. sampling: 'average',
  233. smooth: true,
  234. symbol: 'none',
  235. lineStyle: {
  236. width: 1,
  237. opacity: 0.8,
  238. },
  239. },
  240. ],
  241. }
  242. }
  243. // VOL配置项
  244. const setVolOption = () => {
  245. const { dimensions, source } = dataset.vol;
  246. options.vol = {
  247. ...getDefaultOption(),
  248. dataset: {
  249. dimensions,
  250. source,
  251. },
  252. series: [
  253. {
  254. name: 'VOL',
  255. type: 'bar',
  256. sampling: 'average',
  257. barWidth: '60%',
  258. },
  259. ],
  260. }
  261. }
  262. // KDJ配置项
  263. const setKdjOption = () => {
  264. const { dimensions, source } = dataset.kdj;
  265. options.kdj = {
  266. ...getDefaultOption(),
  267. dataset: {
  268. dimensions,
  269. source,
  270. },
  271. series: [
  272. {
  273. name: 'K',
  274. type: 'line',
  275. sampling: 'average',
  276. smooth: true,
  277. symbol: 'none',
  278. lineStyle: {
  279. width: 1,
  280. opacity: 0.8,
  281. },
  282. },
  283. {
  284. name: 'D',
  285. type: 'line',
  286. sampling: 'average',
  287. smooth: true,
  288. symbol: 'none',
  289. lineStyle: {
  290. width: 1,
  291. opacity: 0.8,
  292. },
  293. },
  294. {
  295. name: 'J',
  296. type: 'line',
  297. sampling: 'average',
  298. smooth: true,
  299. symbol: 'none',
  300. lineStyle: {
  301. width: 1,
  302. opacity: 0.8,
  303. },
  304. },
  305. ],
  306. }
  307. }
  308. // CCI配置项
  309. const setCciOption = () => {
  310. const { dimensions, source } = dataset.cci;
  311. options.cci = {
  312. ...getDefaultOption(),
  313. dataset: {
  314. dimensions,
  315. source,
  316. },
  317. series: [
  318. {
  319. name: 'CCI',
  320. type: 'line',
  321. sampling: 'average',
  322. smooth: true,
  323. symbol: 'none',
  324. lineStyle: {
  325. width: 1,
  326. opacity: 0.8,
  327. },
  328. },
  329. ],
  330. }
  331. }
  332. const initOptions = () => {
  333. setCandlestickOption();
  334. setMacdOption();
  335. setVolOption();
  336. setKdjOption();
  337. setCciOption();
  338. }
  339. // 动态更新数据
  340. const updateOptions = timerInterceptor.setThrottle(() => {
  341. const { candlestick, macd, vol, kdj, cci } = dataset;
  342. options.candlestick = {
  343. dataset: {
  344. source: candlestick.source,
  345. },
  346. series: [
  347. {
  348. name: 'K线',
  349. markLine: {
  350. data: [
  351. {
  352. yAxis: candlestick.source[candlestick.source.length - 1].close,
  353. },
  354. ],
  355. },
  356. },
  357. ],
  358. }
  359. options.macd = {
  360. dataset: {
  361. source: macd.source,
  362. },
  363. }
  364. options.vol = {
  365. dataset: {
  366. source: vol.source,
  367. },
  368. }
  369. options.kdj = {
  370. dataset: {
  371. source: kdj.source,
  372. },
  373. }
  374. options.cci = {
  375. dataset: {
  376. source: cci.source,
  377. },
  378. }
  379. }, 50)
  380. // 监听主题变化
  381. watch(appTheme, () => {
  382. options.colors = getColors();
  383. initOptions();
  384. })
  385. return {
  386. options,
  387. initOptions,
  388. updateOptions,
  389. }
  390. }