TimeLineChart.vue 5.1 KB

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