index.jsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { defineComponent, onMounted, ref, onUnmounted, computed, watch, toRefs } from 'vue'
  2. import * as echarts from 'echarts'
  3. import { bind, clear } from 'size-sensor'
  4. import { map, groupBy, debounce } from 'lodash'
  5. import { NAME, GROUP, VALUE, OPTION, CONFIG_ERROR, BAR_OPTION } from './const'
  6. import { Encode } from './method'
  7. import './common.less'
  8. /**
  9. * 组件提供默认option, 也支持自定义
  10. * dataset为数据集,传入时需要指定绑定字段,默认为name,value;当存在多维数据时需要指定group
  11. * dataset example
  12. * [
  13. * { name: '邮件营销', value: 120, group: '周一' },
  14. { name: '邮件营销', value: 110, group: '周二' },
  15. { name: '邮件营销', value: 99, group: '周三' },
  16. { name: '联盟广告', value: 11, group: '周一' },
  17. { name: '联盟广告', value: 21, group: '周二' },
  18. { name: '联盟广告', value: 31, group: '周三' },
  19. { name: '视频广告', value: 91, group: '周一' },
  20. { name: '视频广告', value: 41, group: '周二' },
  21. { name: '视频广告', value: 41, group: '周三' }
  22. ]
  23. */
  24. export default defineComponent({
  25. name: 'CipCharts',
  26. props: {
  27. options: {
  28. type: Object,
  29. default: () => OPTION
  30. },
  31. dataset: {
  32. type: Array,
  33. default: () => []
  34. },
  35. bindProps: {
  36. type: Object,
  37. default: () => ({
  38. name: NAME,
  39. value: VALUE,
  40. group: GROUP
  41. })
  42. }
  43. },
  44. emits: ['chart-init'],
  45. setup (props, { emit }) {
  46. const chartRef = ref()
  47. let charts = null
  48. const { dataset, options, bindProps } = toRefs(props)
  49. const groupData = computed(() => {
  50. return groupBy(dataset.value, bindProps.value.group ?? GROUP)
  51. })
  52. // 判断是否存在group
  53. const isSingleGroup = computed(() => {
  54. return Object.keys(groupData.value)[0] === 'undefined'
  55. })
  56. // 获取dataset
  57. const _dataset = computed(() => {
  58. const keys = Object.keys(groupData.value)
  59. const _name = bindProps.value.name
  60. const _value = bindProps.value.value
  61. if (isSingleGroup.value) return dataset.value.map(item => ({ ...item, [VALUE]: item[_value], name: item[_name] }))
  62. const result = keys.map(currentKey => {
  63. const currentData = groupData.value[currentKey].reduce((obj, item) => {
  64. obj[item[_name]] = item[_value]
  65. return obj
  66. }, {})
  67. return {
  68. name: currentKey,
  69. ...currentData
  70. }
  71. })
  72. return result
  73. })
  74. // 获取dimensions
  75. const dimensions = computed(() => {
  76. const groups = [...new Set(map(dataset.value, bindProps.value.name))]
  77. return (groups?.length && !isSingleGroup.value) ? [NAME, ...groups] : [NAME, VALUE]
  78. })
  79. // 判断series是否存在,不存在则给默认值;series中如何存在data,则data的优先级高
  80. const series = computed(() => {
  81. const EncodeInstance = new Encode(props.bindProps)
  82. if (options.value.series?.length) return EncodeInstance.checkEncode(options.value.series)
  83. else {
  84. const generateSeries = Array.from({ length: dimensions.value.length - 1 }).map(() => ({
  85. ...BAR_OPTION
  86. }))
  87. return generateSeries.length > 1 ? generateSeries : EncodeInstance.checkEncode(generateSeries)
  88. }
  89. })
  90. // 处理option数据
  91. const chartsOption = computed(() => {
  92. // const legend = Object.assign({}, options.value.legend || {}, {
  93. // show: !isSingleGroup.value
  94. // })
  95. return Object.assign({},
  96. OPTION,
  97. options.value,
  98. // { legend },
  99. isHasDataset.value ? {} : {
  100. dataset: {
  101. dimensions: dimensions.value,
  102. source: _dataset.value
  103. }
  104. }, { series: series.value })
  105. })
  106. // 判断option中是否存在dataset, 存在在则使用option配置
  107. const isHasDataset = computed(() => {
  108. return 'dataset' in options.value
  109. })
  110. // 图表resize
  111. const bindResize = () => {
  112. chartRef.value && bind(chartRef.value, debounce(() => {
  113. charts && charts.resize()
  114. }, 500))
  115. }
  116. // 组合echats的options
  117. onMounted(() => {
  118. charts = echarts.init(chartRef.value)
  119. try {
  120. console.log(chartsOption.value, 'chartsOption')
  121. charts.setOption(chartsOption.value)
  122. bindResize()
  123. emit('chart-init', charts)
  124. } catch (error) {
  125. console.error(CONFIG_ERROR)
  126. }
  127. })
  128. // 销毁实例
  129. onUnmounted(() => {
  130. if (charts) {
  131. charts.dispose()
  132. charts = null
  133. chartRef.value && clear(chartRef.value)
  134. }
  135. })
  136. watch([options, dataset], () => {
  137. try {
  138. charts.clear()
  139. charts.setOption(chartsOption.value)
  140. } catch (error) {
  141. console.error(CONFIG_ERROR)
  142. }
  143. }, {
  144. deep: true
  145. })
  146. return () => <div ref={chartRef} class="cip-chart-wrapper"></div>
  147. }
  148. })