echarts实例:双轴水平条形图(菱形和三角形的symbol)

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

html 复制代码
import { defineComponent } from 'vue'
import { FONT_SIZE } from './createChart'
const props = {
  propData: {
    type: Array,
    default: () => [
      ['年份', '左侧(个)', '右侧(件)'],
      [2044, 59.4, 55.1],
      [2045, 54.2, 54.1],
      [2046, 68.4, 63.2],
      [2047, 64.7, 69.1],
      [2048, 76.1, 74.3],
    ],
  },
  ValueMaxMin: {
    type: Array,
    default: () => [
      [0, 100],
      [0, 100],
    ],
  },

  barWidth: {
    type: Number,
    default: 50,
  },
  barLabelDistance: {
    type: Number,
    default: 50,
  },
  YAxisNameRate: {
    type: Number,
    default: 20,
  },
  YAxisNamePosition: {
    type: Number,
    default: 50,
  },

  leftTriangleColorArray: {
    type: Array,
    default: () => ['rgba(26, 132, 211, 0.1)', 'rgba(15, 221, 138, 1)'],
  },
  barColorArray: {
    type: Array,
    default: () => ['rgba(15, 221, 138, 1)', 'rgba(251, 190, 0, 1)'],
  },
  rightDiamondColorArray: {
    type: Array,
    default: () => ['rgba(211, 140, 26, 0)', 'rgba(251, 190, 0, 1)'],
  },
}
function getModifyAlpha(color, alpha) {
  return echarts.color.modifyAlpha(color, alpha)
}

export default defineComponent({
  props,
  data() {
    return {}
  },
  created() {},
  mounted() {
    this.init()
    this.$watch(
      () => this.$props, // 监听整个 props 对象
      () => {
        this.init()
      },
      { deep: true, immediate: false },
    )
  },
  beforeDestroy() {
    this.chart?.dispose?.()
  },
  methods: {
    init() {
      const label = {
        show: true,
        fontSize: FONT_SIZE,
        color: '#fff',
      }
      const axisLine = {
        show: true,
        lineStyle: {
          color: 'rgba(211, 211, 211, 0.6)', // 轴线颜色
          width: 3, // 轴线宽度
          type: 'solid', // 线型:solid(实线)、dashed(虚线)、dotted(点线)
        },
      }
      const grid共同样式 = {
        show: false,
        top: '5%',
        bottom: '10%',
      }

      const props = this._props
      const barWidth = props.barWidth
      const legendColor = props.barColorArray
      const 系列名称names = props.propData[0].slice(1)
      const Y轴名称names = props.propData.slice(1).map((item) => item[0])
      const data1 = props.propData.slice(1).map((item) => item[1])
      const data2 = props.propData.slice(1).map((item) => item[2])
      const maxValue1 = Math.max(...data1)
      const maxValue2 = Math.max(...data2)
      const xAxisMax = Math.ceil(Math.max(maxValue1, maxValue2) / 100) * 100
      const 中间y轴名称占比Proportion = props.YAxisNameRate
      const 中间y轴名称离左距离 = props.YAxisNamePosition

      const 左右柱子占比Proportion = (100 - 中间y轴名称占比Proportion) / 2 - 3
      const 左右柱子标签偏移量offset = props.barLabelDistance
      const 左侧三角形的渐变色 = props.leftTriangleColorArray.length
        ? props.leftTriangleColorArray
        : [getModifyAlpha(legendColor[0], 0.8), getModifyAlpha(legendColor[0], 1)]
      const 右侧菱形的渐变色 = props.rightDiamondColorArray.length
        ? props.rightDiamondColorArray
        : [getModifyAlpha(legendColor[1], 0.8), getModifyAlpha(legendColor[1], 1)]

      const 左侧series通用配置 = {
        data: data1,
        xAxisIndex: 0,
        yAxisIndex: 0,
        gridIndex: 0,
        name: 系列名称names[0],
      }

      const 右侧series通用配置 = {
        data: data2,
        xAxisIndex: 2,
        yAxisIndex: 2,
        gridIndex: 2,
        name: 系列名称names[1],
      }

      const series装饰用途通用配置 = {
        tooltip: { show: false },
        label: { show: false },
        symbolPosition: 'end',
      }

      const 通用模糊效果 = {
        shadowBlur: 10, // 发光模糊度
        shadowOffsetX: 2,
        shadowOffsetY: 4,
        shadowColor: 'rgba(255, 255, 255, 0.5)',
      }

      const option = {
        color: legendColor,
        legend: {
          show: true,
          data: 系列名称names,
          lineStyle: {
            width: 10,
          },
          top: '0%',
          left: '38%',
          textStyle: {
            ...label,
            padding: [0, 0, 0, 30],
          },
          itemHeight: 30,
          itemWidth: 30,
          itemGap: 50,
        },
        tooltip: {
          show: Y轴名称names.length ? true : false,
          trigger: 'axis',
          axisPointer: {
            type: 'none',
          },
          textStyle: {
            ...label,
          },
          appendToBody: true,
          backgroundColor: '#0C3E5F',
          borderColor: '#0CB6FF',
          borderWidth: 4,
          formatter: (params) => {
            let result = ''
            params.forEach((param) => {
              const value = param.value || 0
              const seriesName = param.seriesName
              // 提取出括号中的单位
              const match = param.seriesName.match(/\((.*?)\)/)
              const unit = match ? match[1] : ''
              // 提取出颜色
              let color = param.color.colorStops[0]?.color || '#ffffff'
              color = getModifyAlpha(color, 1)

              const marker = `<span style="${this.getSerieSymbolStyle(color)}"></span>`
              result += `${marker} ${seriesName} :${value}   ${unit}<br/>`
            })
            return result
          },
        },
        grid: [
          {
            ...grid共同样式,
            left: '8%',
            width: `${左右柱子占比Proportion}%`,
          },
          {
            ...grid共同样式,
            left: `${中间y轴名称离左距离}%`,
            width: `${中间y轴名称占比Proportion}%`,
          },
          {
            ...grid共同样式,
            right: '8%',
            width: `${左右柱子占比Proportion}%`,
          },
        ],
        xAxis: [
          {
            gridIndex: 0,
            type: 'value',
            inverse: true,
            max: this.ValueMaxMin[0][1],
            min: this.ValueMaxMin[0][0],

            // 轴线
            axisLine: {
              ...axisLine,
            },
            axisTick: {
              show: false,
            },
            position: 'bottom',
            axisLabel: {
              ...label,
              textStyle: {
                color: '#fff',
              },
            },
            splitLine: {
              show: false,
            },
          },
          {
            gridIndex: 1,
            show: false,
          },
          {
            gridIndex: 2,
            type: 'value',
            inverse: false,
            max: this.ValueMaxMin[1][1],
            min: this.ValueMaxMin[1][0],

            axisLine: {
              ...axisLine,
            },
            axisTick: {
              show: false,
            },
            position: 'bottom',
            axisLabel: {
              ...label,
              textStyle: {
                color: '#fff',
              },
            },
            splitLine: {
              show: false,
            },
          },
        ],
        yAxis: [
          {
            gridIndex: 0,
            show: true,
            type: 'category',
            inverse: true,
            data: Y轴名称names,
            position: 'right',
            // 轴线
            axisLine: {
              ...axisLine,
            },
            axisTick: {
              show: false,
            },
            axisLabel: {
              show: false,
            },
            splitLine: {
              show: false,
            },
          },
          {
            gridIndex: 1,
            show: true,
            type: 'category',
            inverse: true,
            position: 'center',
            data: Y轴名称names,
            axisLine: {
              show: false,
            },
            axisTick: {
              show: false,
            },
            axisLabel: {
              ...label,
              align: 'center', // 或 'center'
              verticalAlign: 'middle',
              textStyle: {
                color: '#fff',
                padding: [0, 0, 0, 0],
              },
              formatter: (params) => {
                // 这里可以自定义y轴标签样式
                return params
              },
            },
            splitLine: {
              show: false,
            },
          },
          {
            gridIndex: 2,
            show: true,
            type: 'category',
            inverse: true,
            data: Y轴名称names,
            // 轴线
            axisLine: {
              ...axisLine,
            },
            axisTick: {
              show: false,
            },
            axisLabel: {
              show: false,
            },
            splitLine: {
              show: false,
            },
          },
        ],
        series: [
          // 左侧外三角形
          {
            ...左侧series通用配置,
            ...series装饰用途通用配置,
            type: 'pictorialBar',
            symbol: 'triangle',
            symbolSize: [barWidth, barWidth * 0.7],
            symbolRotate: -90,
            symbolOffset: [-25, 0],
            itemStyle: {
              color: {
                type: 'linear',
                x: 0,
                y: 1,
                x2: 0,
                y2: 0,
                colorStops: [
                  {
                    offset: 0,
                    color: 左侧三角形的渐变色[0],
                  },
                  {
                    offset: 1,
                    color: 左侧三角形的渐变色[1],
                  },
                ],
              },
              ...通用模糊效果,
              shadowColor: 左侧三角形的渐变色[0],
            },
          },

          // 左侧内三角形
          {
            ...左侧series通用配置,
            ...series装饰用途通用配置,
            type: 'pictorialBar',
            symbol: 'triangle',
            symbolSize: [barWidth - 10, barWidth * 0.7 - 10],
            symbolRotate: -90,
            symbolOffset: [-11, 0],
            itemStyle: {
              color: 'transparent',
              borderColor: {
                type: 'linear',
                x: 0,
                y: 1,
                x2: 0,
                y2: 0,
                colorStops: [
                  {
                    offset: 0,
                    color: getModifyAlpha(legendColor[0], 0.1),
                  },
                  {
                    offset: 0.8,
                    color: 'rgba(255, 255, 255, 0.5)',
                  },
                  {
                    offset: 1,
                    color: 'rgba(255, 255, 255, 1)',
                  },
                ],
              },
              ...通用模糊效果,
              borderWidth: 30, // 边框宽度
              borderType: 'solid',
            },
          },

          // 左侧实际柱形
          {
            ...左侧series通用配置,
            type: 'bar',
            barWidth,
            label: {
              ...label,
              offset: [-左右柱子标签偏移量offset, 0],
              position: 'left',
            },
            itemStyle: {
              color: (params) => {
                return new echarts.graphic.LinearGradient(1, 0, 0, 0, [
                  {
                    offset: 0,
                    color: getModifyAlpha(legendColor[0], 0.9),
                  },
                  {
                    offset: 1,
                    color: getModifyAlpha(legendColor[0], 1),
                  },
                ])
              },
              borderColor: getModifyAlpha(legendColor[0], 0.1),
              ...通用模糊效果,
            },
          },
          // 右侧前景条
          {
            ...右侧series通用配置,
            ...series装饰用途通用配置,
            type: 'pictorialBar',
            symbol: 'diamond',
            symbolSize: [barWidth, barWidth * 0.7],
            symbolRotate: 90,
            symbolOffset: [35, 0],
            itemStyle: {
              color: {
                type: 'linear',
                x: 0,
                y: 1,
                x2: 0,
                y2: 0,
                colorStops: [
                  {
                    offset: 0,
                    color: 右侧菱形的渐变色[0],
                  },
                  {
                    offset: 1,
                    color: 右侧菱形的渐变色[1],
                  },
                ],
              },
            },
          },
          {
            ...右侧series通用配置,
            ...series装饰用途通用配置,
            type: 'pictorialBar',
            symbol: 'diamond',
            symbolSize: [barWidth - 6, barWidth * 0.7 - 6],
            symbolRotate: 90,
            symbolOffset: [60, 0],
            itemStyle: {
              color: 'transparent',
              borderColor: {
                type: 'linear',
                x: 0,
                y: 1,
                x2: 0,
                y2: 0,
                colorStops: [
                  {
                    offset: 0,
                    color: getModifyAlpha(legendColor[1], 0.1),
                  },
                  {
                    offset: 0.8,
                    color: 'rgba(255, 255, 255, 0.5)',
                  },
                  {
                    offset: 1,
                    color: 'rgba(255, 255, 255, 1)',
                  },
                ],
              },
              ...通用模糊效果,
              borderWidth: 30, // 边框宽度
              borderType: 'solid',
            },
          },

          // 右侧实际柱形
          {
            ...右侧series通用配置,
            type: 'bar',
            barWidth,
            label: {
              ...label,
              offset: [左右柱子标签偏移量offset, 0],
              position: 'right',
            },
            itemStyle: {
              color: (params) => {
                return new echarts.graphic.LinearGradient(1, 0, 0, 0, [
                  {
                    offset: 1,
                    color: getModifyAlpha(legendColor[1], 0.9),
                  },
                  {
                    offset: 0,
                    color: getModifyAlpha(legendColor[1], 1),
                  },
                ])
              },
              borderColor: getModifyAlpha(legendColor[1], 0.1),
              ...通用模糊效果,
            },
          },
        ],
      }
      this.draw(option)
    },
    draw(option) {
      const dom = this.$refs.chart
      if (!this.chart) {
        this.chart = echarts.init(dom, null, {
          renderer: 'canvas',
        })
      }
      this.chart.setOption(option, true)
    },
    getSerieSymbolStyle(color) {
      const style = {
        display: 'inline-block',
        width: '30px',
        height: '30px',
        'border-radius': '3px',
        'margin-right': '12px',
        'vertical-align': 'middle',
        background: color || '#fff',
      }

      return Object.entries(style)
        .map(([key, value]) => `${key}:${value}`)
        .join(';')
    },
  },
})
相关推荐
这个实现不了1 小时前
echarts实例:雷达图做出时钟效果
echarts
这个实现不了1 小时前
echarts实例:圆环内衬图
echarts
B站_计算机毕业设计之家6 天前
电影知识图谱推荐问答系统 | Python Django系统 Neo4j MySQL Echarts 协同过滤 大数据 人工智能 毕业设计源码(建议收藏)✅
人工智能·python·机器学习·django·毕业设计·echarts·知识图谱
吴声子夜歌13 天前
RxJava——Subscriber
android·echarts·rxjava
小白探索世界欧耶!~14 天前
Vue2项目引入sortablejs实现表格行拖曳排序
前端·javascript·vue.js·经验分享·elementui·html·echarts
吴声子夜歌17 天前
RxJava——调度器Scheduler
android·echarts·rxjava
吴声子夜歌17 天前
RxJava——并行编程
android·echarts·rxjava
吴声子夜歌20 天前
RxJava——FlowableProcessor详解
android·echarts·rxjava
B站_计算机毕业设计之家20 天前
电影市场预测分析系统 | Python Django Echarts 票房可视化分析 大数据 人工智能 毕业设计源码(建议收藏)✅
大数据·数据库·python·机器学习·django·毕业设计·echarts