column-chart.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <script setup lang="ts">
  2. /**
  3. * @Name: column-chart.vue
  4. * @Description: 表格内的折线图
  5. * @Author: Cheney
  6. */
  7. import { PropType, ref, onMounted, onUnmounted, watch } from 'vue';
  8. import * as echarts from 'echarts';
  9. const props = defineProps({
  10. rowData: {
  11. type: Object,
  12. required: true,
  13. },
  14. });
  15. const chartRef = ref<HTMLElement | null>(null);
  16. let chart: echarts.ECharts | null = null;
  17. let resizeObserver: ResizeObserver | null = null;
  18. onMounted(() => {
  19. initChart();
  20. });
  21. onUnmounted(() => {
  22. // 清理 ResizeObserver
  23. if (resizeObserver) {
  24. resizeObserver.disconnect();
  25. }
  26. if (chart) {
  27. chart.dispose();
  28. chart = null;
  29. }
  30. });
  31. watch(
  32. () => props.rowData,
  33. () => {
  34. updateChart();
  35. },
  36. { immediate: true, deep: true }
  37. );
  38. function updateChart() {
  39. if (!chart || !props.rowData) return;
  40. const dates = Object.keys(props.rowData.searchFrequencyRank[0]);
  41. const searchFrequencyValues = Object.values(props.rowData.searchFrequencyRank[0]);
  42. const clickShareValues = Object.values(props.rowData.clickShare[0]);
  43. const conversionShareValues = Object.values(props.rowData.conversionShare[0]);
  44. const option: echarts.EChartsOption = {
  45. xAxis: {
  46. type: 'category',
  47. data: dates,
  48. axisLabel: {
  49. rotate: 45,
  50. interval: 0,
  51. },
  52. },
  53. yAxis: [
  54. {
  55. id: 0,
  56. type: 'value',
  57. name: 'Search Frequency Rank',
  58. nameTextStyle: {
  59. fontWeight: 'bold',
  60. fontSize: 14,
  61. color: '#333'
  62. },
  63. splitLine: {
  64. show: true, // 设置显示分割线
  65. },
  66. },
  67. {
  68. id: 1,
  69. type: 'value',
  70. name: 'Share Rate',
  71. nameTextStyle: {
  72. fontWeight: 'bold',
  73. fontSize: 14,
  74. color: '#333'
  75. },
  76. position: 'right',
  77. splitLine: {
  78. show: false, // 设置显示分割线
  79. },
  80. axisLabel: {
  81. formatter: '{value}%',
  82. },
  83. // axisLine: {
  84. // show: true,
  85. // },
  86. // show: true,
  87. },
  88. ],
  89. series: [
  90. {
  91. name: 'Search Frequency Rank',
  92. data: searchFrequencyValues,
  93. type: 'bar',
  94. barWidth: '18px',
  95. itemStyle: {
  96. color: '',
  97. borderRadius: [4, 4, 4, 4],
  98. },
  99. yAxisIndex: 0,
  100. },
  101. {
  102. name: 'Click Share',
  103. data: clickShareValues,
  104. type: 'line',
  105. yAxisIndex: 1,
  106. },
  107. {
  108. name: 'Conversion Share',
  109. data: conversionShareValues,
  110. type: 'line',
  111. yAxisIndex: 1,
  112. },
  113. ],
  114. tooltip: {
  115. trigger: 'axis',
  116. formatter: function(params) {
  117. let result = params[0].axisValueLabel + '<br/>';
  118. params.forEach(param => {
  119. let value = param.value;
  120. if (param.seriesName === 'Click Share' || param.seriesName === 'Conversion Share') {
  121. value = value + '%';
  122. } else if (param.seriesName === 'Search Frequency Rank') {
  123. value = value.toLocaleString(); // 使用逗号分隔
  124. }
  125. result += param.marker + ' ' + param.seriesName + ': ' + value + '<br/>';
  126. });
  127. return result;
  128. }
  129. },
  130. legend: {
  131. data: ['Search Frequency Rank', 'Click Share', 'Conversion Share'],
  132. },
  133. };
  134. chart.setOption(option);
  135. }
  136. function initChart() {
  137. if (chartRef.value) {
  138. chart = echarts.init(chartRef.value);
  139. updateChart();
  140. // 创建 ResizeObserver
  141. resizeObserver = new ResizeObserver(() => {
  142. chart?.resize();
  143. });
  144. // 观察 chartRef 元素
  145. resizeObserver.observe(chartRef.value);
  146. }
  147. }
  148. </script>
  149. <template>
  150. <div ref="chartRef" style="width: 100%; height: 300px"></div>
  151. </template>
  152. <style scoped></style>