zhou zhou
10 小时以前 46d872c1a5b77aa8799de4a64888a0a24a1422d6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<!-- 环形图 -->
<template>
  <div
    ref="chartRef"
    class="relative w-full"
    :style="{ height: props.height }"
    v-loading="props.loading"
  >
  </div>
</template>
 
<script setup>
  import { useChartOps, useChartComponent } from '@/hooks/core/useChart'
  defineOptions({ name: 'ArtRingChart' })
  const props = defineProps({
    height: { required: false, default: useChartOps().chartHeight },
    loading: { required: false, default: false },
    isEmpty: { required: false, default: false },
    colors: { required: false, default: () => useChartOps().colors },
    data: { required: false, default: () => [] },
    radius: { required: false, default: () => ['50%', '80%'] },
    borderRadius: { required: false, default: 10 },
    centerText: { required: false, default: '' },
    showLabel: { required: false, default: false },
    showTooltip: { required: false, default: true },
    showLegend: { required: false, default: false },
    legendPosition: { required: false, default: 'right' }
  })
  const { chartRef, isDark, getAnimationConfig, getTooltipStyle, getLegendStyle } =
    useChartComponent({
      props,
      checkEmpty: () => {
        return !props.data?.length || props.data.every((item) => item.value === 0)
      },
      watchSources: [() => props.data, () => props.centerText],
      generateOptions: () => {
        const getCenterPosition = () => {
          if (!props.showLegend) return ['50%', '50%']
          switch (props.legendPosition) {
            case 'left':
              return ['60%', '50%']
            case 'right':
              return ['40%', '50%']
            case 'top':
              return ['50%', '60%']
            case 'bottom':
              return ['50%', '40%']
            default:
              return ['50%', '50%']
          }
        }
        const option = {
          tooltip: props.showTooltip
            ? getTooltipStyle('item', {
                formatter: '{b}: {c} ({d}%)'
              })
            : void 0,
          legend: props.showLegend ? getLegendStyle(props.legendPosition) : void 0,
          series: [
            {
              name: '数据占比',
              type: 'pie',
              radius: props.radius,
              center: getCenterPosition(),
              avoidLabelOverlap: false,
              itemStyle: {
                borderRadius: props.borderRadius,
                borderColor: isDark.value ? '#2c2c2c' : '#fff',
                borderWidth: 0
              },
              label: {
                show: props.showLabel,
                formatter: '{b}\n{d}%',
                position: 'outside',
                color: isDark.value ? '#ccc' : '#999',
                fontSize: 12
              },
              emphasis: {
                label: {
                  show: false,
                  fontSize: 14,
                  fontWeight: 'bold'
                }
              },
              labelLine: {
                show: props.showLabel,
                length: 15,
                length2: 25,
                smooth: true
              },
              data: props.data,
              color: props.colors,
              ...getAnimationConfig(),
              animationType: 'expansion'
            }
          ]
        }
        if (props.centerText) {
          const centerPos = getCenterPosition()
          option.title = {
            text: props.centerText,
            left: centerPos[0],
            top: centerPos[1],
            textAlign: 'center',
            textVerticalAlign: 'middle',
            textStyle: {
              fontSize: 18,
              fontWeight: 500,
              color: isDark.value ? '#999' : '#ADB0BC'
            }
          }
        }
        return option
      }
    })
</script>