TimeLineChart.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <script setup lang="ts">
  2. import type { OptionsProps } from '@/types/dataAnalysis'
  3. import { onMounted, ref, shallowRef, watch, useAttrs } from 'vue'
  4. import { nextTick } from 'vue'
  5. import { debounceFunc } from '@/utils/common'
  6. import echarts from '.'
  7. // 图表需要的props
  8. const props = defineProps<OptionsProps>()
  9. // 传入的attrs
  10. const attrs = useAttrs()
  11. // 图表实例
  12. const linechart = shallowRef()
  13. // 图表Ref
  14. const chart = ref()
  15. // 颜色
  16. const colorList = [
  17. '#00e070',
  18. '#1495eb',
  19. '#993333', // Dark Red
  20. '#FFD700', // Bright Yellow
  21. '#FF00FF', // Magenta
  22. '#FFA500', // Orange
  23. '#800080', // Dark Purple
  24. '#A52A2A', // Brown
  25. '#FF4500', // Orange Red
  26. '#FF6347', // Tomato
  27. '#B22222', // Firebrick
  28. '#FF1493' // Deep Pink
  29. ]
  30. // 格式化tooltip
  31. const formatterTooltip = (params: Array<any>) => {
  32. let circle = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:`
  33. let result = `<span style="font-weight:bold;">${params[0].axisValueLabel}</span>`
  34. params.map((item, index) => {
  35. let data = `${circle}${colorList[index]}"></span>
  36. <span >
  37. <span style="display: inline-block; box-sizing: border-box;
  38. padding-right: 50px;">${item['seriesName']}</span><span>${item['value']}<span>`
  39. result += `<br/>${data}`
  40. })
  41. return result
  42. }
  43. // 尺寸变化
  44. const changeSize = () => {
  45. nextTick(() => {
  46. linechart.value?.resize()
  47. })
  48. }
  49. // 初始化options
  50. const initOptions = () => {
  51. // 选项
  52. let options: any = {
  53. xAxis: {
  54. type: 'category',
  55. data: [],
  56. axisLabel: {
  57. showMaxLabel: true
  58. },
  59. axisTick: {
  60. alignWithLabel: true
  61. }
  62. },
  63. yAxis: {
  64. type: 'value',
  65. minInterval: 1
  66. },
  67. tooltip: {
  68. trigger: 'axis',
  69. formatter: formatterTooltip
  70. },
  71. legend: {
  72. orient: 'horizontal', //图例布局方式:水平 'horizontal' 、垂直 'vertical'
  73. x: 'right', // 横向放置位置,选项:'center'、'left'、'right'、'number'(横向值 px)
  74. y: 'top', // 纵向放置位置,选项:'top'、'bottom'、'center'、'number'(纵向值 px)
  75. data: []
  76. },
  77. grid: {
  78. left: '24px',
  79. right: '10px',
  80. containLabel: true
  81. },
  82. series: []
  83. }
  84. // 基本的series数据配置
  85. let baseSeries = {
  86. symbol: 'circle',
  87. symbolSize: 5,
  88. showSymbol: false,
  89. // itemStyle要在lineStyle前面,这个item会把line的样式覆盖掉,并且必须要有line,不然也会被item替换掉
  90. itemStyle: {
  91. color: 'rgb(255,255,255)',
  92. borderColor: '#1495eb', // symbol边框颜色
  93. borderWidth: 2 // symbol边框宽度
  94. },
  95. lineStyle: {
  96. color: '#1495eb'
  97. },
  98. name: '今日新增',
  99. data: [10, 22, 28, 43, 49],
  100. type: 'line',
  101. smooth: true
  102. }
  103. linechart.value.clear()
  104. if (props.seriesData.length) {
  105. // 最终的siries数组
  106. let finalSeriesList: any = []
  107. props.legendData.map((item, index) => {
  108. const seriesClone = JSON.parse(JSON.stringify(baseSeries))
  109. // 设置克隆的属性
  110. seriesClone.name = item
  111. let reuslt = props.seriesData.find((val) => {
  112. return val.name === item
  113. })
  114. seriesClone.data = Object.values(reuslt.data)
  115. seriesClone.itemStyle.borderColor = colorList[index]
  116. seriesClone.lineStyle.color = colorList[index]
  117. // 将克隆后的对象添加到 finalSeriesList 中
  118. finalSeriesList.push(seriesClone)
  119. })
  120. options.series = finalSeriesList
  121. options.legend.data = Object.values(props.legendData as any)
  122. options.xAxis.data = props.xAxisData as any
  123. } else {
  124. options = {
  125. title: {
  126. text: '暂无数据',
  127. x: 'center',
  128. y: 'center',
  129. textStyle: {
  130. fontSize: 16,
  131. fontWeight: 'normal'
  132. }
  133. }
  134. }
  135. }
  136. linechart.value.setOption(options, true)
  137. }
  138. // 改变加载状态
  139. const changeLoading = (state: boolean) => {
  140. if (state) linechart.value.showLoading()
  141. else linechart.value.hideLoading()
  142. }
  143. // 监听options信息的变化
  144. watch(
  145. () => [props.legendData, props.seriesData, props.xAxisData],
  146. () => {
  147. initOptions()
  148. },
  149. { deep: true }
  150. )
  151. watch(
  152. () => attrs['loading-state'] as boolean,
  153. (newval: boolean) => {
  154. changeLoading(newval)
  155. },
  156. { deep: true }
  157. )
  158. onMounted(() => {
  159. nextTick(() => {
  160. // 开始的时候,不要去直接初始化,先展示加载状态,等到数据加载完状态改变,再去设置
  161. linechart.value = echarts.init(chart.value)
  162. if (!attrs['loading-state']) initOptions()
  163. /**
  164. * @description: 只监听window会导致当侧边栏缩放时,dom大小变化但无法resize
  165. * 所以需要使用ovserver对整个dom进行监听
  166. * @return {*}
  167. */
  168. // window.addEventListener('resize', debounceFunc(changeSize, 500))
  169. const debounceChangeSize = debounceFunc(changeSize, 200)
  170. const ro = new ResizeObserver(debounceChangeSize)
  171. ro.observe(chart.value)
  172. })
  173. })
  174. </script>
  175. <template>
  176. <div class="chart" ref="chart" style="width: 100%; height: 365px"></div>
  177. </template>
  178. <style scoped>
  179. .t {
  180. color: red;
  181. display: inline-block;
  182. box-sizing: border-box;
  183. padding-right: 20px;
  184. }
  185. </style>