echarts实例:进度条加描述

0 阅读1分钟

记录下工作中使用echarts做出的特殊组件

image.png

import { defineComponent } from 'vue'
import { FONT_SIZE, COLOR_LIGHT_ORG, COLOR_YELLOW, COLOR_LIGHT_GREEN } from './createChart'


let props = {
  propData: {
    type: Array,
    default: () => [
      { name: '名称1', value: 353, color: COLOR_YELLOW, desc: '{x}条描述' },
      { name: '名称2', value: 85, color: COLOR_LIGHT_GREEN, desc: '{2}条描述' },
      { name: '名称3', value: 30, color: '#FF6B6B', desc: '包括{名称3} XX{2}条描述,XX{4}条描述,XX{2}条描述' },
      { name: '名称4', value: 8, color: '#00BAAE', desc: '' },
    ],
  },
  barWidth: {
    default: 25,
    type: Number,
  },
}
const colors = [COLOR_LIGHT_ORG, COLOR_YELLOW, COLOR_LIGHT_GREEN, '#7B68EE', '#FF6B6B', '#4ECDC4'] // 添加更多备用颜色


export default defineComponent({
  props,
  data() {
    return {
      fontSize: FONT_SIZE + 4,
    }
  },
  created() {},
  mounted() {
    this.init()
    this.$watch(
      () => this.$props, // 监听整个 props 对象
      () => {
        this.init()
      },
      { deep: true, immediate: false },
    )
  },
  beforeDestroy() {
    this.chart?.dispose?.()
  },
  methods: {
    init() {
      const option = this.getOption() // 间隙
      const dom = this.$refs.chart
      if (!this.chart) {
        this.chart = echarts.init(dom, null, {
          renderer: 'canvas',
        })
      }
      this.chart.setOption(option, true)
    },
    getOption() {
      if (!this.propData.length) return {}
      const seriesdata = this.getData()
      const series = this.getSeries(seriesdata)
      const maxValue = this.getMaxValue(this.propData)
      const seriesBg = this.getBackgroundBarSeries(maxValue)
      return {
        legend: {
          show: false,
        },
        tooltip: {
          show: false,
        },
        grid: {
          left: '6%',
          right: '5%',
          bottom: '0%',
          top: '1%',
          containLabel: true,
        },
        xAxis: [
          {
            type: 'value',
            axisLine: {
              show: false,
            },
            splitLine: {
              show: false,
            },
            axisLabel: {
              show: false,
            },
            axisTick: {
              show: false,
            },
          },
        ],
        yAxis: [
          {
            type: 'category',
            data: _.map(this.propData, 'name'),
            axisLine: {
              show: false,
            },
            splitLine: {
              show: false,
            },
            axisLabel: {
              show: true,
              fontSize: this.fontSize,
              textStyle: {
                color: '#fff',
              },
              align: 'left', // 左对齐
              padding: [0, 0, 0, -150], // 去掉内边距
              interval: 0,
            },
            axisTick: {
              show: false,
            },
          },
          {
            type: 'category',
            data: this.propData,
            offSet: -10,
            axisLine: {
              show: false,
            },
            splitLine: {
              show: false,
            },
            axisLabel: {
              show: false,
            },
            axisTick: {
              show: false,
            },
          },
          {
            type: 'category',
            data: this.propData,
            axisLine: {
              show: false,
            },
            splitLine: {
              show: false,
            },
            axisLabel: {
              show: false,
            },
            axisTick: {
              show: false,
            },
          },
        ],
        series: [...seriesBg, ...series],
      }
    },

    // 获取最大值
    getMaxValue(data) {
      const values = _.map(data, 'value')
      return Math.max(...values)
    },
    getData() {
      return this.propData.map((item, index) => {
        const color = item.color || colors[index] || '#ffffff'
        return {
          ...item,
          label: {
            show: true,
            position: [0, 0],
            fontSize: this.fontSize - 5,
            offset: [20, -70],
            color: '#fff',
            formatter: (params, index) => {
              const text = this.propData[params.dataIndex]?.desc || ''
              // 将文本拆分成数组,然后组合成富文本字符串
              const parts = text.split(/(\{[^}]+\})/)
              let richText = ''
              parts.forEach((part) => {
                if (part.startsWith('{') && part.endsWith('}')) {
                  // 移除花括号
                  const value = part.substring(1, part.length - 1)
                  richText += `{num|${value}}`
                } else if (part) {
                  richText += part
                }
              })
              return richText
            },
            rich: {
              num: {
                color, // 动态颜色
                fontSize: this.fontSize ,
                padding: [0, 5, 0, 5],
              },
            },
          },
          itemStyle: {
            color: {
              type: 'linear',
              x: 0,
              y: 0, // 上
              x2: 1,
              y2: 0, // 下
              colorStops: [
                {
                  offset: 0,
                  color: echarts.color.modifyAlpha(color, 0.1),
                },
                {
                  offset: 0.3,
                  color: echarts.color.modifyAlpha(color, 0.6),
                },
                {
                  offset: 1,
                  color: echarts.color.modifyAlpha(color, 1),
                },
              ],
            },
            shadowColor: 'rgba(255,255,255,0.2)',
            shadowBlur: 5,
            shadowOffsetX: 0,
            shadowOffsetY: 0,
          },
        }
      })
    },
    getSeries(data) {
      return [
        {
          name: '主系列',
          type: 'bar',
          stack: 'total',
          barWidth: this.barWidth,
          yAxisIndex: 0,
          z: 2,
          data,
        },
      ]
    },
    // 最大值为背景底部进度条
    getBackgroundBarSeries(maxValue) {
      const config = {
        data: this.propData.map(() => {
          return maxValue
        }),
        tooltip: { show: false },
        showInLegend: false,
      }
      const series = [
        {
          ...config,
          type: 'bar',
          name: '背景bar',
          barWidth: this.barWidth,
          itemStyle: {
            color: 'rgba(255, 255, 255,0.13)',
            borderWidth: 0,
          },

          yAxisIndex: 1,
        },
        {
          ...config,
          type: 'bar',
          name: '背景框',
          data: this.propData.map((i, index) => {
            return {
              value: maxValue + 5,
              label: {
                color: this.propData[index]?.color || '#fff',
              },
            }
          }),
          barWidth: this.barWidth + 20,
          itemStyle: {
            color: 'rgba(255, 255, 255,0)',
            borderColor: '#fff',
            borderWidth: 2,
            borderRadius: 0,
          },
          label: {
            show: true,
            position: 'right',
            fontSize: this.fontSize+10,
            fontFamily: 'TRENDS',
            offset: [50, 0],
            formatter: (params) => {
              return this.propData[params.dataIndex]?.value || 0
            },
          },
          yAxisIndex: 2,
        },
      ]
      return series
    },
  },
})