Newer
Older
safe_production_front / src / components / Echart / radarChart.vue
dutingting on 6 Mar 4 KB 多租户、jessibucaPro组件
<script lang="ts" setup name="PieChart">
import type { ECharts } from 'echarts'
import { init, number } from 'echarts'
import type { Ref } from 'vue'
import type { ECBasicOption } from 'echarts/types/dist/shared'
import tdTheme from './theme.json' // 引入默认主题
const props = defineProps({
  /**
   * id
   */
  id: {
    type: String,
    default: 'chart',
  },
  /**
   * 加载中
   */
  loading: {
    type: Boolean,
    default: false,
  },
  /**
   * 标题
   */
  title: {
    type: String,
    default: '',
  },
  /**
   * 图例是否显示
   */
  legend: {
    type: Object,
    default: () => {
      return {
        show: true,
        type: 'scroll',
        orient: 'horizontal',
        right: '10%',
        top: 'top',
        icon: 'circle',
        itemWidth: 16,
        itemHeight: 16,
        itemStyle: {
          fontSize: 16,
        },
      }
    },
  },
  /**
   * 网格配置
   */
  grid: {
    type: Object,
    default: () => {
      return {
        top: 0,
        left: '15%',
        right: '50%',
        bottom: 50,
        containLabel: true, // 是否包含坐标轴的刻度标签
      }
    },
  },
  /**
   * 图表宽
   */
  width: {
    type: String,
    default: '100%',
  },
  /**
   * 图表高
   */
  height: {
    type: String,
    default: '100%',
  },
  /**
   * 距离容器右侧距离,默认0,为legend在右侧时做准备
   */
  right: {
    type: [Number, String],
    default: 0,
  },
  /**
   * 数据
   */
  data: {
    type: Array,
    default: () => { return [] },
  },
  unit: {
    type: String,
    default: '',
  },
  /**
   * 悬停格式化
   */
  hoverFormatter: {
    type: String,
    default: '{b}<br/>数量:{c}' + '<br/>占比:{d}%',
  },
  radar: {
    type: Object,
  },
  /**
   * 颜色
   */
  colors: {
    type: Array,
    default: () => {
      return [
        '#46edf2',
        '#45c7f2',
        '#ff9900',
        '#E46CBB',
        '#9A66E4',
        '#ed3f14',
        '#01C2F9',
      ]
    },
  },
})

// 图表对象
let chart: ECharts
const chartRef: Ref<HTMLElement | null> = ref(null)

// 监听数据变化
watch(
  [() => props.data], ([newNums], [oldNums]) => {
    refreshChart()
  },
  {
    immediate: true,
    deep: true,
  },
)
// 构建option
function buildOption() {
  const option: any = {
    title: [{ text: props.title }],
    legend: props.legend, // 图例
    grid: props.grid, // 网格
    tooltip: {
      show: true,
      confine: true, // 是否限制提示框在图表范围内
      trigger: 'item',
      // formatter: `{b}<br/>数量:{c}${props.unit}<br/>占比:{d}%`,
      textStyle: {
        fontSize: 14,
        color: '#fff',
      },
      backgroundColor: 'rgba(3, 53, 139, .9)',
    }, // 提示框
    series: [],
  }
  // 标题
  if (props.title) {
    option.title = {
      show: true,
      text: props.title,
      textStyle: {
        fontWeight: 'normal',
        fontSize: 14,
        color: '#0b2c5b',
      },
      bottom: 0,
      left: 'center',
    }
  }
  // 标题
  if (props.colors) {
    option.color = props.colors as string[]
  }
  // 数据
  if (props.data) {
    const series = {
      type: 'radar',
      center: ['50%', '50%'], // 圆心坐标[横坐标,纵坐标]
      right: props.right,
      itemStyle: {
        borderColor: '#fff',
        borderWidth: 1,
        borderRadius: 8,
      },
      label: {
        fontSize: 16,
      },
      data: props.data,
    }
    option.series = [series]
  }
  if (props.radar) {
    const radarData = {
      indicator: props.radar,
      nameGap: 5, // 文字距离
      radius: '55%', // 图比例大小
      axisName: {
        color: '#a1cfd1',
      },
      splitLine: { // (这里是指所有圆环)坐标轴在 grid 区域中的分隔线。
        lineStyle: {
          color: '#89aeb2',
          // 分隔线颜色
          width: 2,
          // 分隔线线宽
        },
      },
      splitArea: {
        show: true,
        areaStyle: {
          // color: '#89aeb2', // 图表背景网格的颜色
        },
      },
      name: { // 文本名称样式
        textStyle: {
          color: '#a1cfd1',
        },
      },
    }
    option.radar = radarData
  }
  return option
}
// 初始化图表
function initChart() {
  chart = init(chartRef.value as HTMLElement, tdTheme)
  chart.setOption({})
}

// 刷新图表
function refreshChart() {
  if (chart) {
    const option = buildOption()
    chart.setOption(option as unknown as ECBasicOption, true)
    chart.resize()
  }
}

window.addEventListener('resize', () => {
  chart.resize()
})

onMounted(() => {
  initChart()
})
</script>

<template>
  <div :id="id" ref="chartRef" v-loading="loading" class="chart" :style="{ height, width }" />
</template>

<style lang="scss" scoped>
.chart {
  width: 100%;
  height: 100%;
  z-index: 100;
}
</style>