其他分享
首页 > 其他分享> > react封装echarts仪表盘

react封装echarts仪表盘

作者:互联网

1、仪表盘组件

  GaugeChart/index.tsx(组件中的nightFlag是适配黑夜模式,获取公共状态中的值)

import React, { useEffect, useRef } from 'react'
import styles from './index.less'
import { connect } from 'umi'
import { ConnectState } from '@/models/connect'
// echarts
import * as echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/gauge'

interface GaugeProps {
  name: string // 仪表盘名称
  unit: string // 单位
  target?: number // 目标值
  sprint?: number // 冲刺值
  current?: number // 当前值
  nightFlag?: boolean // 是否开了黑夜模式
}
const GaugeChart: React.FC<GaugeProps> = (props) => {
  let chartInstance: any = null // 图表实例
  const chartRef = useRef(null)
  const { name, unit, target = 0, sprint = 0, current = 0, nightFlag } = props
  const hasTargetAndSprint = !!(target && sprint) // 是否有目标值和冲刺值

  const max = (sprint: number, target: number, current: number) => {
    if (sprint) return Math.ceil(sprint / 5) * 5
    if (target) return Math.ceil(target / 5) * 5
    if (current) return Math.ceil(current / 5) * 5
    return 100
  }
  const option = {
    series: [
      {
        type: 'gauge',
        max: max(sprint, target, current), // 最大值的优先级顺序:冲刺值 任务值 当前值 100
        axisLine: {
          roundCap: true,
          lineStyle: {
            width: 10,
            color: hasTargetAndSprint
              ? [
                  [target / max(sprint, target, current), '#416EFF'],
                  [1, '#FF6565']
                ]
              : [[1, '#416EFF']]
          }
        },
        anchor: {
          show: true,
          showAbove: true,
          size: 12,
          itemStyle: {
            color: '#fff',
            borderColor: current > target && hasTargetAndSprint ? '#FF6565' : '#416EFF',
            borderWidth: 1
          }
        }, // 空心圆圈
        pointer: { width: 5, length: '55%', offsetCenter: [0, -5], itemStyle: { color: 'auto' } }, // 指针
        axisTick: { distance: 10, length: 8, lineStyle: { color: 'auto', width: 2 } }, // 虚线
        splitLine: { lineStyle: { width: 0 } }, // 当前值 虚线 的宽度
        axisLabel: { color: 'inherit', distance: 20, fontSize: 10 }, // 进度数字 0 10 20 30 40 50 60...
        detail: { valueAnimation: true, color: 'inherit', fontSize: 30, offsetCenter: [0, '70%'] }, // 当前值
        data: [
          {
            value: current,
            name: name,
            title: {
              fontSize: '16',
              color: nightFlag ? '#fff' : '#373A44',
              offsetCenter: [0, '90%']
            }
          }
        ]
      }
    ]
  }

  // 初始化
  const initChart = () => {
    const renderedInstance = echarts.getInstanceByDom(chartRef.current)
    if (renderedInstance) {
      chartInstance = renderedInstance
    } else {
      chartInstance = echarts.init(chartRef.current)
    }
    chartInstance.setOption(option)
  }
  useEffect(() => {
    initChart()
    return () => {
      chartInstance && chartInstance.dispose()
    }
  }, [nightFlag])

  return (
    <div className={styles.gaugeChartContainer}>
      <div
        style={
          hasTargetAndSprint
            ? { width: '500px', height: '400px' }
            : { width: '500px', height: '400px', opacity: 0.8 }
        }
        ref={chartRef}
      ></div>
      {/* {hasTargetAndSprint ? ( */}
      <ul className={styles.legend}>
        <li>
          <i></i>任务指标:{target}
          {unit}
        </li>
        <li>
          <i></i>冲刺指标:{sprint}
          {unit}
        </li>
      </ul>
      {/* ) : null} */}
    </div>
  )
}

// export default GaugeChart
export default connect(({ night: { nightFlag } }: ConnectState) => ({ nightFlag }))(GaugeChart)

  GaugeChart/index.less

.gaugeChartContainer {
  position: relative;
  margin-bottom: 20px;
  ul.legend {
    position: absolute;
    bottom: 20px;
    display: flex;
    justify-content: space-around;
    width: 100%;
    margin-bottom: 0;
    padding-left: 0;
    li {
      display: flex;
      align-items: center;
      color: var(--theme-text-color);
      font-size: 14px;
      i {
        display: block;
        width: 20px;
        height: 12px;
        margin-right: 8px;
        background-image: linear-gradient(90deg, #6489ff 0%, #416eff 100%);
      }
      &:last-of-type i {
        background-image: linear-gradient(90deg, #ff926d 0%, #ff6565 100%);
      }
    }
  }
}
View Code

 

2、使用

  gaugeOptions是一个数组(数据结构中label和value是提供给下拉框组件使用的,仪表盘组件中不需要)

[
    {
        "label": "销售额",
        "value": 0,
        "name": "销售额(万元)",
        "unit": "万元",
        "target": 49.000066,
        "sprint": 100,
        "current": "82.6"
    },
    {
        "label": "实收款",
        "value": 1,
        "name": "实收款(万元)",
        "unit": "万元",
        "target": 0,
        "sprint": 0,
        "current": "82.9"
    },
    {
        "label": "新拓客户",
        "value": 2,
        "name": "新拓客户(个)",
        "unit": "个",
        "target": 51,
        "sprint": 200,
        "current": 0
    },
    {
        "label": "续签客户",
        "value": 3,
        "name": "续签客户(个)",
        "unit": "个",
        "target": 55,
        "sprint": 300,
        "current": 0
    },
    {
        "label": "至尊占比",
        "value": 4,
        "name": "至尊占比(%)",
        "unit": "%",
        "target": 10000,
        "sprint": 0,
        "current": 35.45
    },
    {
        "label": "普及率",
        "value": 5,
        "name": "普及率(%)",
        "unit": "%",
        "target": 45,
        "sprint": 120,
        "current": 25.03
    }
]

  DOM

        {gaugeOptions.map((item) => (
          <GaugeChart
            key={item.value}
            unit={item.unit}
            name={item.name}
            target={item.target}
            sprint={item.sprint}
            current={item.current}
          />
        ))}

 

3、效果

  

 

标签:current,封装,target,color,react,sprint,echarts,unit,name
来源: https://www.cnblogs.com/wuqilang/p/15963390.html