黄石人流数据大屏
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.

157 lines
4.3 KiB

2 weeks ago
  1. <template>
  2. <div ref="chart" class="chart-box" />
  3. </template>
  4. <script>
  5. import { debounce } from '@/utils/index'
  6. export default {
  7. name: 'YearInFlowChart',
  8. props: {
  9. yearData: {
  10. type: Array,
  11. default: () => []
  12. }
  13. },
  14. data() {
  15. return {
  16. chart: null,
  17. ro: null
  18. }
  19. },
  20. computed: {
  21. xAxis() {
  22. return this.yearData.map((i) => i.month + '月')
  23. },
  24. series() {
  25. return this.yearData.map((i) => i.count || 0)
  26. }
  27. },
  28. watch: {
  29. yearData() {
  30. this.setOption()
  31. }
  32. },
  33. mounted() {
  34. this.$nextTick(() => this.initChart())
  35. },
  36. beforeDestroy() {
  37. this.stopTipLoop()
  38. if (this.ro) {
  39. this.ro.disconnect()
  40. this.ro = null
  41. }
  42. if (this.chart) {
  43. this.chart.dispose()
  44. this.chart = null
  45. }
  46. },
  47. methods: {
  48. initChart() {
  49. this.chart = this.$echarts.init(this.$refs.chart)
  50. this.setOption()
  51. // 用 ResizeObserver 监听容器自身尺寸变化,比 window.resize 更可靠
  52. const doResize = debounce(() => {
  53. if (this.chart) this.chart.resize()
  54. }, 100)
  55. this.ro = new ResizeObserver(() => doResize())
  56. this.ro.observe(this.$refs.chart)
  57. },
  58. setOption() {
  59. if (!this.chart) return
  60. const idx = Math.max(0, this.series.length - 1)
  61. const lastVal = this.series[idx]
  62. this.chart.setOption({
  63. tooltip: {
  64. trigger: 'axis',
  65. backgroundColor: 'rgba(11, 26, 48, 0.92)',
  66. borderColor: '#18E3A7',
  67. textStyle: { color: '#e2e8f0', fontSize: 14 },
  68. axisPointer: { type: 'line', lineStyle: { color: '#18E3A7' }}
  69. },
  70. grid: { left: 40, right: 20, top: 50, bottom: 30, containLabel: false },
  71. xAxis: {
  72. type: 'category',
  73. data: this.xAxis,
  74. boundaryGap: false,
  75. axisLine: { lineStyle: { color: 'rgba(24,227,167,0.4)' }},
  76. axisTick: { show: false },
  77. axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12, interval: 'auto' },
  78. splitLine: { show: false }
  79. },
  80. yAxis: {
  81. type: 'value',
  82. min: 0,
  83. max: (v) => v.max === 0 ? 100 : Math.ceil(v.max * 1.25),
  84. axisLine: { show: false },
  85. axisTick: { show: false },
  86. axisLabel: { color: 'rgba(255,255,255,0.6)', fontSize: 12 },
  87. splitLine: { lineStyle: { color: 'rgba(24,227,167,0.12)', type: 'dashed' }}
  88. },
  89. series: [{
  90. name: '进馆人次',
  91. type: 'line',
  92. smooth: true,
  93. symbol: 'none',
  94. showSymbol: false,
  95. data: this.series,
  96. lineStyle: { color: '#18E3A7', width: 3, shadowColor: '#18E3A7', shadowBlur: 12 },
  97. itemStyle: { color: '#18E3A7' },
  98. areaStyle: {
  99. color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
  100. { offset: 0, color: 'rgba(24,227,167,0.45)' },
  101. { offset: 1, color: 'rgba(24,227,167,0.02)' }
  102. ])
  103. },
  104. markPoint: {
  105. symbol: 'circle',
  106. symbolSize: 12,
  107. label: {
  108. position: 'top',
  109. distance: 12,
  110. formatter: () => String(lastVal),
  111. fontSize: 26,
  112. fontWeight: 800,
  113. color: '#fff',
  114. textShadowColor: 'rgba(24,227,167,0.8)',
  115. textShadowBlur: 10
  116. },
  117. itemStyle: {
  118. color: '#18E3A7',
  119. shadowColor: 'rgba(24,227,167,1)',
  120. shadowBlur: 12
  121. },
  122. data: [{ coord: [idx, lastVal] }]
  123. }
  124. }]
  125. })
  126. this.startTipLoop()
  127. },
  128. // 动态轮播 tooltip,适配大屏无人交互场景
  129. startTipLoop() {
  130. this.stopTipLoop()
  131. if (!this.series.length) return
  132. this.tipIndex = -1
  133. this.tipTimer = setInterval(() => {
  134. if (!this.chart || !this.series.length) return
  135. this.tipIndex = (this.tipIndex + 1) % this.series.length
  136. this.chart.dispatchAction({
  137. type: 'showTip',
  138. seriesIndex: 0,
  139. dataIndex: this.tipIndex
  140. })
  141. }, 2500)
  142. },
  143. stopTipLoop() {
  144. if (this.tipTimer) {
  145. clearInterval(this.tipTimer)
  146. this.tipTimer = null
  147. }
  148. }
  149. }
  150. }
  151. </script>
  152. <style lang="scss">
  153. @import "~@/assets/styles/index.scss";
  154. </style>