options.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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 - 120, // 起始显示K线条数(最新120条)
  54. endValue: source.length,
  55. minValueSpan: 50, // 限制窗口缩放显示最少数据条数
  56. maxValueSpan: 400, // 限制窗口缩放显示最大数据条数
  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. default: {
  86. return moment(params.value).format('YYYY-MM-DD HH:mm:ss')
  87. }
  88. }
  89. },
  90. }
  91. },
  92. axisTick: {
  93. show: false,
  94. }
  95. },
  96. yAxis: {
  97. scale: true,
  98. splitLine: {
  99. lineStyle: {
  100. // 坐标分隔线颜色
  101. color: xAxisLineColor,
  102. },
  103. },
  104. },
  105. }
  106. }
  107. // K线配置项
  108. const setCandlestickOption = () => {
  109. const { dimensions, source } = dataset.candlestick;
  110. const { upColor, downColor } = options.colors;
  111. options.candlestick = {
  112. ...getDefaultOption(),
  113. dataset: {
  114. dimensions,
  115. source,
  116. },
  117. series: [
  118. {
  119. name: 'K线',
  120. type: 'candlestick',
  121. itemStyle: {
  122. color: upColor,
  123. color0: downColor,
  124. borderColor: upColor,
  125. borderColor0: downColor,
  126. },
  127. // 最新价标线
  128. markLine: {
  129. symbolSize: 6,
  130. // 标线标签样式
  131. label: {
  132. color: '#fff',
  133. backgroundColor: 'rgba(128,128,128,.75)',
  134. padding: 5,
  135. borderRadius: 3,
  136. position: 'insideStartTop',
  137. },
  138. // 标线样式
  139. lineStyle: {
  140. type: 'dashed',
  141. color: 'rgba(102,102,102,.6)'
  142. },
  143. data: [
  144. {
  145. // 收盘价
  146. yAxis: source.length ? source[source.length - 1].close : 0,
  147. },
  148. ],
  149. },
  150. },
  151. {
  152. name: 'MA5',
  153. type: 'line',
  154. sampling: 'average', //折线图在数据量远大于像素点时候的降采样策略,开启后可以有效的优化图表的绘制效率
  155. smooth: true,
  156. symbol: 'none',
  157. lineStyle: {
  158. width: 1,
  159. opacity: 0.8,
  160. },
  161. },
  162. {
  163. name: 'MA10',
  164. type: 'line',
  165. sampling: 'average',
  166. smooth: true,
  167. symbol: 'none',
  168. lineStyle: {
  169. width: 1,
  170. opacity: 0.8,
  171. },
  172. },
  173. {
  174. name: 'MA15',
  175. type: 'line',
  176. sampling: 'average',
  177. smooth: true,
  178. symbol: 'none',
  179. lineStyle: {
  180. width: 1,
  181. opacity: 0.8,
  182. },
  183. },
  184. ],
  185. }
  186. }
  187. // MACD配置项
  188. const setMacdOption = () => {
  189. const { upColor, downColor } = options.colors;
  190. const { dimensions, source } = dataset.macd;
  191. options.macd = {
  192. ...getDefaultOption(),
  193. dataset: {
  194. dimensions,
  195. source,
  196. },
  197. series: [
  198. {
  199. name: 'MACD',
  200. type: 'bar',
  201. sampling: 'average',
  202. barWidth: '20%',
  203. itemStyle: {
  204. color: ({ data }) => {
  205. const { macd } = data as { macd: number };
  206. if (macd > 0) {
  207. return upColor;
  208. } else {
  209. return downColor;
  210. }
  211. },
  212. }
  213. },
  214. {
  215. name: 'DIF',
  216. type: 'line',
  217. sampling: 'average',
  218. smooth: true,
  219. symbol: 'none',
  220. lineStyle: {
  221. width: 1,
  222. opacity: 0.8,
  223. },
  224. },
  225. {
  226. name: 'DEA',
  227. type: 'line',
  228. sampling: 'average',
  229. smooth: true,
  230. symbol: 'none',
  231. lineStyle: {
  232. width: 1,
  233. opacity: 0.8,
  234. },
  235. },
  236. ],
  237. }
  238. }
  239. // VOL配置项
  240. const setVolOption = () => {
  241. const { dimensions, source } = dataset.vol;
  242. options.vol = {
  243. ...getDefaultOption(),
  244. dataset: {
  245. dimensions,
  246. source,
  247. },
  248. series: [
  249. {
  250. name: 'VOL',
  251. type: 'bar',
  252. sampling: 'average',
  253. barWidth: '60%',
  254. },
  255. ],
  256. }
  257. }
  258. // KDJ配置项
  259. const setKdjOption = () => {
  260. const { dimensions, source } = dataset.kdj;
  261. options.kdj = {
  262. ...getDefaultOption(),
  263. dataset: {
  264. dimensions,
  265. source,
  266. },
  267. series: [
  268. {
  269. name: 'K',
  270. type: 'line',
  271. sampling: 'average',
  272. smooth: true,
  273. symbol: 'none',
  274. lineStyle: {
  275. width: 1,
  276. opacity: 0.8,
  277. },
  278. },
  279. {
  280. name: 'D',
  281. type: 'line',
  282. sampling: 'average',
  283. smooth: true,
  284. symbol: 'none',
  285. lineStyle: {
  286. width: 1,
  287. opacity: 0.8,
  288. },
  289. },
  290. {
  291. name: 'J',
  292. type: 'line',
  293. sampling: 'average',
  294. smooth: true,
  295. symbol: 'none',
  296. lineStyle: {
  297. width: 1,
  298. opacity: 0.8,
  299. },
  300. },
  301. ],
  302. }
  303. }
  304. // CCI配置项
  305. const setCciOption = () => {
  306. const { dimensions, source } = dataset.cci;
  307. options.cci = {
  308. ...getDefaultOption(),
  309. dataset: {
  310. dimensions,
  311. source,
  312. },
  313. series: [
  314. {
  315. name: 'CCI',
  316. type: 'line',
  317. sampling: 'average',
  318. smooth: true,
  319. symbol: 'none',
  320. lineStyle: {
  321. width: 1,
  322. opacity: 0.8,
  323. },
  324. },
  325. ],
  326. }
  327. }
  328. const initOptions = () => {
  329. setCandlestickOption();
  330. setMacdOption();
  331. setVolOption();
  332. setKdjOption();
  333. setCciOption();
  334. }
  335. // 动态更新数据
  336. const updateOptions = timerInterceptor.setThrottle(() => {
  337. const { candlestick, macd, vol, kdj, cci } = dataset;
  338. options.candlestick = {
  339. dataset: {
  340. source: candlestick.source,
  341. },
  342. series: [
  343. {
  344. name: 'K线',
  345. markLine: {
  346. data: [
  347. {
  348. yAxis: candlestick.source[candlestick.source.length - 1].close,
  349. },
  350. ],
  351. },
  352. },
  353. ],
  354. }
  355. options.macd = {
  356. dataset: {
  357. source: macd.source,
  358. },
  359. }
  360. options.vol = {
  361. dataset: {
  362. source: vol.source,
  363. },
  364. }
  365. options.kdj = {
  366. dataset: {
  367. source: kdj.source,
  368. },
  369. }
  370. options.cci = {
  371. dataset: {
  372. source: cci.source,
  373. },
  374. }
  375. }, 100)
  376. // 监听主题变化
  377. watch(appTheme, () => {
  378. options.colors = getColors();
  379. initOptions();
  380. })
  381. return {
  382. options,
  383. initOptions,
  384. updateOptions,
  385. }
  386. }