You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
14 KiB

3 weeks ago
3 weeks ago
3 weeks ago
  1. <template>
  2. <div ref="bottomRadarRef" id="bottomRadarChart" style="heigh: 100%; width: 100%;"></div>
  3. </template>
  4. <script setup>
  5. import { ref } from 'vue'
  6. import * as echarts from 'echarts'
  7. const bottomRadarRef = ref(null)
  8. let bottomRadarChart = null
  9. function initEmotionalBottomRadar(KlineData, barAndLineData) {
  10. let bottomRadarChartDom = document.getElementById('bottomRadarChart')
  11. bottomRadarChart = echarts.init(bottomRadarChartDom)
  12. // 日期-作为x轴
  13. let dateArray = KlineData.map(subArray => subArray[0])
  14. // k线,取前四个即可
  15. let kLineDataArray = KlineData.map(subArray => subArray.slice(1, 5))
  16. // 红线,取第二个值
  17. let redLineDataArray = barAndLineData.map(subArray => subArray[1])
  18. // 色块数据格式化
  19. let barTotalDataArray = barAndLineData.map(subArray => subArray.slice(2, 6))
  20. // 删掉
  21. // barTotalDataArray[0] = [0, 0, 0, 0]
  22. // barTotalDataArray[8] = [1, 1, 1, 1]
  23. // barTotalDataArray[9] = [0, 0, 1, 1]
  24. // barTotalDataArray[13] = [1, 0, 1, 0]
  25. // barTotalDataArray[16] = [0, 0, 1, 0]
  26. // 黄色块、黄色加仓资金、紫色柱子、蓝色柱子
  27. let yellowBlockDataArray = []
  28. let yellowLineDataArray = []
  29. let purpleLineDataArray = []
  30. let blueLineDataArray = []
  31. let transparentFillingDataArray = []
  32. // 黄色块:为1 0-4显示柱体
  33. // 黄色加仓资金文字:为1 在4的位置展示文字
  34. // 紫色柱子:为1 1-80显示柱体
  35. // 蓝色柱子:为1 0-40显示柱体
  36. // 因数据要互相叠加展示,所以需要数据处理。base适用于 ECharts 4.x 及以上版本
  37. barTotalDataArray.forEach((item) => {
  38. if (item[0]) {
  39. yellowBlockDataArray.push(4)
  40. if (item[3]) {
  41. // 40-4
  42. blueLineDataArray.push(36)
  43. if (item[2]) {
  44. // 80-40
  45. purpleLineDataArray.push(40)
  46. transparentFillingDataArray.push(0)
  47. } else {
  48. purpleLineDataArray.push(0)
  49. transparentFillingDataArray.push(0)
  50. }
  51. } else {
  52. blueLineDataArray.push(0)
  53. if (item[2]) {
  54. // 80-4
  55. purpleLineDataArray.push(76)
  56. transparentFillingDataArray.push(0)
  57. } else {
  58. purpleLineDataArray.push(0)
  59. transparentFillingDataArray.push(0)
  60. }
  61. }
  62. } else if (!item[0]) {
  63. yellowBlockDataArray.push(0)
  64. if (item[3]) {
  65. blueLineDataArray.push(40)
  66. if (item[2]) {
  67. // 80-40
  68. purpleLineDataArray.push(40)
  69. transparentFillingDataArray.push(0)
  70. } else {
  71. purpleLineDataArray.push(0)
  72. transparentFillingDataArray.push(0)
  73. }
  74. } else {
  75. blueLineDataArray.push(0)
  76. if (item[2]) {
  77. // 80-1,base为1
  78. purpleLineDataArray.push(79)
  79. transparentFillingDataArray.push(1)
  80. } else {
  81. purpleLineDataArray.push(0)
  82. transparentFillingDataArray.push(0)
  83. }
  84. }
  85. }
  86. // 加仓资金
  87. if (item[1]) {
  88. yellowLineDataArray.push(1)
  89. } else if (!item[1]) {
  90. yellowLineDataArray.push(0)
  91. }
  92. })
  93. // 配置图表选项,很多操作和展示已限制,如果需要需放开
  94. let option = {
  95. // backgroundColor: '#000046', // 设置整个图表的背景色
  96. tooltip: {
  97. show: false, // 不展示tip
  98. // 当前echart版本十字准星独立渲染了; 4.x+才有showAxisPointer
  99. trigger: 'axis',
  100. axisPointer: {
  101. type: 'cross',
  102. crossStyle: {
  103. color: '#999'
  104. }
  105. },
  106. backgroundColor: 'rgba(255, 255, 255, 0.8)',
  107. borderColor: '#ccc',
  108. borderWidth: 1,
  109. padding: 10,
  110. textStyle: {
  111. color: '#333'
  112. },
  113. formatter: function (params) {
  114. let result = `<div style="font-weight: bold;">${params[0].name}</div>`
  115. params.forEach(param => {
  116. let value = param.value
  117. let color = param.color
  118. if (param.seriesType === 'candlestick') {
  119. result += `<div style="color: ${color}"><i class="fa fa-square mr-1"></i>${param.seriesName}: 开 ${value[0]}, 收 ${value[1]}, 低 ${value[2]}, 高 ${value[3]}</div>`
  120. } else {
  121. result += `<div style="color: ${color}"><i class="fa fa-square mr-1"></i>${param.seriesName}: ${value}</div>`
  122. }
  123. })
  124. return result
  125. }
  126. },
  127. legend: {
  128. // data: ['K线', '红线', '色块'], 不要展示图例
  129. type: 'scroll',
  130. pageButtonItemGap: 2,
  131. pageButtonPosition: 'end',
  132. textStyle: {
  133. color: '#666'
  134. }
  135. },
  136. grid: [
  137. {
  138. left: '3%',
  139. right: '3%',
  140. top: '20px',
  141. bottom: '50%',
  142. height: '300px',
  143. // containLabel: true
  144. },
  145. {
  146. left: '3%',
  147. right: '3%',
  148. top: '320px',
  149. bottom: '25%',
  150. height: '300px',
  151. // containLabel: true
  152. },
  153. {
  154. left: '3%',
  155. right: '3%',
  156. top: '620px',
  157. bottom: '50px',
  158. height: '300px',
  159. // containLabel: true
  160. }
  161. ],
  162. xAxis: [
  163. {
  164. type: 'category',
  165. data: dateArray,
  166. gridIndex: 0,
  167. boundaryGap: true, // 保持间距,不要离y轴太近,不然重叠了
  168. axisLine: {
  169. // show: false,
  170. lineStyle: {
  171. color: '#837b7b', // x轴线颜色
  172. }
  173. },
  174. axisTick: {
  175. show: false
  176. },
  177. axisLabel: {
  178. show: false
  179. },
  180. splitLine: {
  181. show: false // 不要x轴的分割线
  182. },
  183. axisPointer: {
  184. link: {
  185. xAxisIndex: 'all'
  186. }
  187. }
  188. },
  189. {
  190. type: 'category',
  191. data: dateArray,
  192. gridIndex: 1,
  193. boundaryGap: true,
  194. axisLine: {
  195. // show: false,
  196. lineStyle: {
  197. // color: '#008000'
  198. color: '#837b7b'
  199. }
  200. },
  201. axisTick: {
  202. show: false
  203. },
  204. axisLabel: {
  205. show: false
  206. },
  207. splitLine: {
  208. show: false
  209. },
  210. axisPointer: {
  211. link: {
  212. xAxisIndex: 'all'
  213. }
  214. }
  215. },
  216. {
  217. type: 'category',
  218. data: dateArray,
  219. gridIndex: 2,
  220. axisLine: {
  221. lineStyle: {
  222. color: '#837b7b'
  223. }
  224. },
  225. axisTick: {
  226. show: true, // 显示刻度线
  227. alignWithLabel: true,
  228. lineStyle: {
  229. color: '#999', // 颜色
  230. width: 1, // 宽度
  231. type: 'solid' // 线样式(solid/dashed/dotted)
  232. }
  233. },
  234. axisLabel: {
  235. color: '#000000',
  236. interval: 'auto',
  237. rotate: 45
  238. },
  239. splitLine: {
  240. show: false
  241. },
  242. axisPointer: {
  243. link: {
  244. xAxisIndex: 'all'
  245. }
  246. }
  247. }
  248. ],
  249. yAxis: [
  250. {
  251. type: 'value',
  252. gridIndex: 0,
  253. splitNumber: 4,
  254. axisLine: {
  255. lineStyle: {
  256. color: '#837b7b' // y轴坐标轴颜色
  257. }
  258. },
  259. axisTick: {
  260. show: true
  261. },
  262. axisLabel: {
  263. width: 50, // 宽度限制
  264. color: '#000000',
  265. formatter: function (value, index) {
  266. if (index === 0) {
  267. return '0'
  268. }
  269. return value.toFixed(2)
  270. }
  271. },
  272. splitLine: {
  273. show: false,
  274. lineStyle: {
  275. color: '#837b7b',
  276. type: 'dotted' // 设置网格线类型 dotted:虚线 solid:实线
  277. }
  278. },
  279. // min: 4,
  280. scale: true, // 不强制包含0,不然k线图底部空余太多
  281. },
  282. {
  283. type: 'value',
  284. gridIndex: 1,
  285. splitNumber: 3,
  286. axisLine: {
  287. lineStyle: {
  288. color: '#837b7b'
  289. }
  290. },
  291. axisTick: {
  292. show: true
  293. },
  294. splitNumber: 5, // 刻度数量
  295. axisLabel: {
  296. width: 50, // 宽度限制
  297. color: '#000000',
  298. formatter: function(value, index) {
  299. // 如果没有刻度数量,其他方法获取不到y轴刻度总长
  300. if (index === 0) {
  301. return '0'
  302. } else if (index === 5) {
  303. return ''
  304. }
  305. return value
  306. }
  307. },
  308. splitLine: {
  309. show: false,
  310. lineStyle: {
  311. color: '#837b7b',
  312. type: 'dotted'
  313. }
  314. },
  315. },
  316. {
  317. type: 'value',
  318. gridIndex: 2,
  319. splitNumber: 2,
  320. axisLine: {
  321. lineStyle: {
  322. color: '#837b7b'
  323. }
  324. },
  325. axisTick: {
  326. show: true
  327. },
  328. splitNumber: 5, // 刻度数量
  329. axisLabel: {
  330. width: 50, // 宽度限制
  331. color: '#000000',
  332. formatter: function(value, index) {
  333. if (index === 5) {
  334. return ''
  335. }
  336. return value
  337. }
  338. },
  339. splitLine: {
  340. show: false,
  341. lineStyle: {
  342. color: '#837b7b',
  343. type: 'dotted' // 设置网格线类型 dotted:虚线 solid:实线
  344. }
  345. },
  346. splitNumber: 5,
  347. min: function(value) {
  348. return 0 // 最小值
  349. },
  350. max: function(value) {
  351. return value.max + 10 // 比最大值高10, 避免最高点和上一个图表x轴重合
  352. }
  353. }
  354. ],
  355. dataZoom: [
  356. {
  357. type: 'slider',
  358. xAxisIndex: [0, 2],
  359. // start: 80,
  360. // end: 100,
  361. show: false
  362. },
  363. {
  364. type: 'slider',
  365. xAxisIndex: [0, 2],
  366. // start: 80,
  367. // end: 100,
  368. show: false
  369. },
  370. {
  371. type: 'slider',
  372. xAxisIndex: [0, 2],
  373. // 一次性全部 or 后20%
  374. // start: 80,
  375. // end: 100,
  376. show: false, // 先不显示
  377. borderColor: '#CFD6E3',
  378. dataBackground: {
  379. // 线
  380. lineStyle: {
  381. color: '#CFD6E3'
  382. },
  383. // 阴影
  384. areaStyle: {
  385. color: 'rgba(241,243,247,0.5)'
  386. }
  387. }
  388. },
  389. ],
  390. series: [
  391. {
  392. name: 'K线',
  393. type: 'candlestick',
  394. data: kLineDataArray,
  395. xAxisIndex: 0,
  396. yAxisIndex: 0,
  397. itemStyle: {
  398. color: '#ef232a', // 上涨颜色 (红)
  399. color0: '#14b143', // 下跌颜色 (绿)
  400. borderColor: '#ef232a',
  401. borderColor0: '#14b143',
  402. normal: {
  403. color: '#ef232a', // 上涨颜色 (红)
  404. color0: '#14b143', // 下跌颜色 (绿)
  405. borderColor: '#ef232a',
  406. borderColor0: '#14b143',
  407. opacity: function(params) {
  408. // 收盘价 > 开盘价时为阳线,设置边框不透明、填充透明
  409. return params.data[2] > params.data[1] ? 0 : 1
  410. }
  411. }
  412. }
  413. },
  414. {
  415. name: '红线',
  416. type: 'line',
  417. data: redLineDataArray,
  418. xAxisIndex: 1,
  419. yAxisIndex: 1,
  420. symbol: 'none',
  421. sampling: 'average',
  422. itemStyle: {
  423. normal: {
  424. color: '#ef232a'
  425. }
  426. },
  427. areaStyle: {
  428. color: {
  429. type: 'linear',
  430. x: 0,
  431. y: 0,
  432. x2: 0,
  433. y2: 1,
  434. colorStops: [
  435. { offset: 0, color: 'rgba(33, 150, 243, 0.4)' },
  436. { offset: 1, color: 'rgba(33, 150, 243, 0)' }
  437. ]
  438. }
  439. }
  440. },
  441. {
  442. name: '基础base',
  443. type: 'bar',
  444. stack: 'total',
  445. // barGap: '-100%', // 重叠
  446. xAxisIndex: 2,
  447. yAxisIndex: 2,
  448. barCategoryGap: '0%',
  449. itemStyle: {
  450. normal: {
  451. color: '#ffffff',
  452. borderWidth: 0,
  453. }
  454. },
  455. data: transparentFillingDataArray,
  456. },
  457. {
  458. name: '黄色块',
  459. type: 'bar',
  460. stack: 'total',
  461. // barGap: '-100%', // 重叠
  462. xAxisIndex: 2,
  463. yAxisIndex: 2,
  464. barCategoryGap: '0%', // 类目间柱条间距为0
  465. itemStyle: {
  466. normal: {
  467. color: 'rgba(255, 255, 0, 1)',
  468. borderWidth: 0,
  469. // 加仓资金的文字显示
  470. label: {
  471. show: (params) => {
  472. return yellowLineDataArray[params.dataIndex] > 0
  473. },
  474. position: 'top',
  475. textStyle: {
  476. color: 'rgba(255, 255, 0, 1)'
  477. },
  478. formatter: (params) => {
  479. return yellowLineDataArray[params.dataIndex] > 0 ? '加仓资金' : ''
  480. }
  481. }
  482. }
  483. },
  484. data: yellowBlockDataArray,
  485. },
  486. {
  487. name: '蓝色',
  488. type: 'bar',
  489. stack: 'total',
  490. xAxisIndex: 2,
  491. yAxisIndex: 2,
  492. barCategoryGap: '0%', // 类目间柱条间距为0
  493. label: {
  494. show: true,
  495. position: 'inside'
  496. },
  497. itemStyle: {
  498. normal: {
  499. color: 'rgba(34, 196, 190, 1)',
  500. borderWidth: 0
  501. }
  502. },
  503. data: blueLineDataArray
  504. },
  505. {
  506. name: '紫色',
  507. type: 'bar',
  508. stack: 'total',
  509. xAxisIndex: 2,
  510. yAxisIndex: 2,
  511. barCategoryGap: '0%', // 类目间柱条间距为0
  512. label: {
  513. show: true,
  514. position: 'inside'
  515. },
  516. itemStyle: {
  517. normal: {
  518. color: 'rgba(191, 87, 222, 1)',
  519. borderWidth: 0
  520. }
  521. },
  522. data: purpleLineDataArray
  523. },
  524. ]
  525. }
  526. // 使用配置项显示图表
  527. bottomRadarChart.setOption(option)
  528. // 监听窗口大小变化,调整图表尺寸
  529. window.addEventListener('resize', () => {
  530. bottomRadarChart.resize()
  531. })
  532. }
  533. // 暴露给父级
  534. defineExpose({
  535. initEmotionalBottomRadar
  536. })
  537. onBeforeUnmount(() => {
  538. // 组件卸载时销毁图表
  539. if (bottomRadarChart) {
  540. bottomRadarChart.dispose()
  541. }
  542. })
  543. </script>
  544. <style>
  545. #bottomRadarChart{
  546. min-width: 100%;
  547. /* min-height: 100%; */
  548. height:1040px;
  549. /* padding-bottom: 3rem; */
  550. }
  551. </style>