ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

react封装echarts仪表盘

2022-03-04 11:03:36  阅读:175  来源: 互联网

标签:current 封装 target color react sprint echarts unit name


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有