echarts图表案例分享

390 阅读8分钟

1. 项目图表案例

1.1 3D柱状图

  • 示例 vkc4w8.png

  • option (值大于120时改变柱体样式)

    const trendData = [120, 200, 150, 80, 70, 110, 130, 120, 200, 150, 80, 70] // 展示数据
    const option = {
      //x轴
      xAxis: {
        type: 'category', //坐标轴类型
        //type: 'value' 数值轴,适用于连续数据。
        //type: 'category' 类目轴,适用于离散的类目数据。为该类型时类目数据可自动从 series.data 或 dataset.source 中取,
        // 或者可通过 xAxis.data 设置类目数据。,category与data一起使用
        axisLine: {
          show: true,
          lineStyle: {
            color: 'rgba(63, 157, 221, 0.5)',
            width: 2
          }
        },
        axisTick: {
          show: false
        },
        name: '月',
        nameTextStyle: {
          color: '#59B8F6',
          fontSize: 13,
          fontFamily: 'TRENDS'
        },
        axisLabel: {
          color: '#59B8F6',
          fontSize: 13,
          fontFamily: 'TRENDS',
          margin: 20,
          formatter: function (value, index) {
            return index + 1
          }
        }
      },
      // y轴
      yAxis: {
        type: 'value',
        name: 'kw·h',
        nameTextStyle: {
          color: '#59B8F6',
          fontSize: 13,
          fontFamily: 'TRENDS'
        },
        axisLabel: {
          color: '#59B8F6',
          fontSize: 13,
          fontFamily: 'TRENDS',
          margin: 20
        },
        axisLine: {
          show: true,
          lineStyle: {
            color: 'rgba(63, 157, 221, 0.5)',
            width: 2
          }
        },
        splitLine: {
          lineStyle: {
            color: 'rgba(11, 104, 135, 0.5)',
            width: 2
          }
        }
      },
      tooltip: {
        show: false
      },
      // 直角坐标系内绘图网格
      grid: {
        // left: 20,
        left: 0,
        right: '15%',
        top: '20%',
        containLabel: true //设置自适应画布大小状态为开,也可通过设置left左移实现相同效果。这常用于『防止标签溢出』的场景,标签溢出指的是,标签长度动态变化时,可能会溢出容器或者覆盖其他组件。
      },
      // 图例组件
      legend: {
        bottom: '5%'
      },
      series: [
        { // 背景柱顶图形
          z: 1, //控制图形的前后顺序
          type: 'pictorialBar',
          symbolPosition: 'end',
          //symbolPosition:'start':图形边缘与柱子开始的地方内切。
          // symbolPosition:'end':图形边缘与柱子结束的地方内切。
          // symbolPosition:'center':图形在柱子里居中。
          data: [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200],
          symbol: 'diamond',
          symbolOffset: [0, '-50%'],
          symbolSize: [18, 18 * 0.4],
          itemStyle: {
            normal: {
              color: 'rgba(68, 145, 195, 0.6)'
            }
          }
        },
        { // 主体柱状图
          type: 'bar',
          barWidth: '18', // 柱条的宽度,不设时自适应。
          data: trendData.map((item) => {
            let itemStyle =
              item > 120
                ? {
                    //图形样式。
                    color: {
                      type: 'linear',
                      x: 0,
                      x2: 1,
                      y: 0,
                      y2: 0,
                      colorStops: [
                        {
                          offset: 0,
                          color: 'rgba(249, 189, 112, 0.7)'
                        },
                        {
                          offset: 0.6,
                          color: 'rgba(249, 189, 112, 1)'
                        },
                        {
                          offset: 0.7,
                          color: 'rgba(244, 136, 0, 1)'
                        },
                        {
                          offset: 1,
                          color: 'rgba(244, 136, 0, 0.8)'
                        },
                        {
                          offset: 0,
                          color: 'rgba(249, 167, 62, 0.5)'
                        }
                      ]
                    }
                  }
                : {
                    //图形样式。
                    color: {
                      type: 'linear',
                      x: 0,
                      x2: 1,
                      y: 0,
                      y2: 0,
                      colorStops: [
                        {
                          offset: 0,
                          color: 'rgba(134, 231, 255, 0.5)'
                        },
                        {
                          offset: 0.6,
                          color: 'rgba(134, 231, 255, 0.7)'
                        },
                        {
                          offset: 0.7,
                          color: 'rgba(5, 148, 197, 0.7)'
                        },
                        {
                          offset: 1,
                          color: 'rgba(5, 148, 197, 0.5)'
                        },
                        {
                          offset: 0,
                          color: 'rgba(17,166,208,0.4)'
                        }
                      ]
                    }
                  }
            return {
              value: item,
              itemStyle
            }
          }),
          showBackground: true,
          label: {
            show: true,
            position: 'top',
            fontSize: 18,
            fontFamily: 'DINAlternate-Bold, DINAlternate',
            fontWeight: 'bold',
            formatter: (param) => {
              return `{${param.value > 120 ? 'a' : 'b'}|${param.value}}`
            },
            rich: {
              a: {
                color: '#F48800',
                fontSize: 18,
                fontFamily: 'DINAlternate-Bold, DINAlternate',
                fontWeight: 'bold'
              },
              b: {
                color: '#EBF7FF',
                fontSize: 18,
                fontFamily: 'DINAlternate-Bold, DINAlternate',
                fontWeight: 'bold'
              }
            }
          },
          backgroundStyle: {
            color: {
              type: 'linear',
              x: 0,
              x2: 1,
              y: 0,
              y2: 0,
              colorStops: [
                {
                  offset: 0,
                  color: 'rgba(29, 82, 117, 0.5)'
                },
                {
                  offset: 0.6,
                  color: 'rgba(29, 82, 117, 0.6)'
                },
                {
                  offset: 0.7,
                  color: 'rgba(0, 62, 101, 0.6)'
                },
                {
                  offset: 0.7,
                  color: 'rgba(0, 62, 101, 0.5)'
                },
                {
                  offset: 1,
                  color: 'rgba(0, 62, 101, 0.5)'
                },
                {
                  offset: 0,
                  color: 'red'
                },
                {
                  offset: 0,
                  color: 'rgba(29, 82, 117, 0.2)'
                }
              ]
            }
          }
        },
        { // 柱底图形
          z: 2, //控制图形的前后顺序
          symbolPosition: 'start',
          //symbolPosition:'start':图形边缘与柱子开始的地方内切。
          // symbolPosition:'end':图形边缘与柱子结束的地方内切。
          // symbolPosition:'center':图形在柱子里居中。
          type: 'pictorialBar', //象形柱图是可以设置各种具象图形元素
          data: trendData.map((item) => {
            let itemStyle =
              item > 120
                ? {
                    //图形样式。
                    color: {
                      type: 'linear',
                      x: 0,
                      x2: 1,
                      y: 0,
                      y2: 0,
                      colorStops: [
                        {
                          offset: 0,
                          color: 'rgba(249, 189, 112, 0.7)'
                        },
                        {
                          offset: 0.6,
                          color: 'rgba(249, 189, 112, 1)'
                        },
                        {
                          offset: 0.7,
                          color: 'rgba(244, 136, 0, 1)'
                        },
                        {
                          offset: 1,
                          color: 'rgba(244, 136, 0, 0.8)'
                        },
                        {
                          offset: 0,
                          color: 'rgba(249, 167, 62, 0.5)'
                        }
                      ]
                    }
                  }
                : {
                    //图形样式。
                    color: {
                      type: 'linear',
                      x: 0,
                      x2: 1,
                      y: 0,
                      y2: 0,
                      colorStops: [
                        {
                          offset: 0,
                          color: 'rgba(134, 231, 255, 0.5)'
                        },
                        {
                          offset: 0.6,
                          color: 'rgba(134, 231, 255, 0.7)'
                        },
                        {
                          offset: 0.7,
                          color: 'rgba(5, 148, 197, 0.7)'
                        },
                        {
                          offset: 1,
                          color: 'rgba(5, 148, 197, 0.5)'
                        },
                        {
                          offset: 0,
                          color: 'rgba(17,166,208,0.4)'
                        }
                      ]
                    }
                  }
            return {
              value: item,
              itemStyle
            }
          }),
          symbol: 'diamond', // 柱子显示的样式,'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
          symbolOffset: [0, '50%'],
          symbolSize: [18, 5]
        },
        { // 内容部分柱顶图形
          z: 3, //控制图形的前后顺序
          type: 'pictorialBar',
          symbolPosition: 'end',
          //symbolPosition:'start':图形边缘与柱子开始的地方内切。
          // symbolPosition:'end':图形边缘与柱子结束的地方内切。
          // symbolPosition:'center':图形在柱子里居中。
          data: trendData.map((item) => {
            return {
              value: item,
              itemStyle: {
                color: item > 120 ? 'rgba(249, 167, 62, 0.8)' : 'rgba(134, 231, 255, 0.6)'
              }
            }
          }),
          symbol: 'diamond',
          symbolOffset: [0, '-50%'],
          symbolSize: [18, 18 * 0.4],
          itemStyle: {
            normal: {
              color: 'rgba(134, 231, 255, 0.6)'
            }
          }
        }
      ]
    }
    

1.2 多label显示的南丁格尔玫瑰图

  • 示例 vk2A3j.png

  • option

    const option = {
      legend: {
        bottom: '15%',
        itemGap: 40,
        itemWidth: 12,
        itemHeight: 12,
        textStyle: {
          color: '#E5FAFA',
          fontSize: 12
        }
      },
      color: ['#04B3EE', '#3234D7', '#AE2FFC', '#F68700', '#F6B500'],
      series: [
        { // 主体图形
          type: 'pie',
          z: 2,
          radius: [0, '55%'],
          center: ['50%', '40%'],
          roseType: 'area',
          startAngle: 180,
          clockwise: false,
          label: {
            show: true,
            position: 'inside',
            formatter: '{d}%',
            color: '#EAEEF4',
            fontSize: 16
          },
          labelLine: {
            show: true,
            length: 10,
            length2: 5
          },
          itemStyle: {},
          data: [
            { value: 40, name: 'rose 1' },
            { value: 38, name: 'rose 2' },
            { value: 32, name: 'rose 3' },
            { value: 30, name: 'rose 4' },
            { value: 28, name: 'rose 5' }
          ]
        },
        { // 激活时的背景图形
          type: 'pie',
          z: 3,
          radius: [0, '55%'],
          center: ['50%', '40%'],
          roseType: 'area',
          startAngle: 180,
          clockwise: false,
          label: {
            normal: {
              show: false,
              formatter: '{d}%',
              color: '#EAEEF4',
              fontSize: 16
            },
            emphasis: {
              show: true,
              fontSize: 16,
              formatter: '{b}\n{c}'
            }
          },
          labelLine: {
            normal: {
              show: false,
              length: 20,
              length2: 20
            },
            emphasis: {
              show: true,
              lineStyle: {
                color: '#EAEEF4'
              }
            }
          },
          itemStyle: {
            normal: {
              color: 'rgba(0, 0, 0, 0)'
            },
            emphasis: {
              color: 'rgba(0, 0, 0, 0.2)'
            }
          },
          emphasis: {
            scaleSize: 20
          },
          data: [
            { value: 40, name: 'rose 1' },
            { value: 38, name: 'rose 2' },
            { value: 32, name: 'rose 3' },
            { value: 30, name: 'rose 4' },
            { value: 28, name: 'rose 5' }
          ]
        }
      ]
    }
    

1.3 多轴折线图

  • 示例 vkRtzj.png

  • option

    const transformerData = reactive({
      dayApparentPower: [],
      dayLoadRate: []
    })
    for (let i = 1; i < 25; i++) {
      transformerData.dayApparentPower.push({
        date: `2022-07-27 ${i}:00`,
        value: (180 * Math.random() + 20).toFixed(2)
      })
    ​
      transformerData.dayLoadRate.push({
        date: `2022-07-27 ${i}:00`,
        value: (150 * Math.random() + 20).toFixed(2)
      })
    }
    const option = {
      grid: {
        bottom: '3%',
        left: '2%',
        top: '20%',
        right: '10%',
        containLabel: true
      },
      legend: {
        top: 10,
        left: -30,
        itemGap: 570,
        icon: 'none',
        textStyle: {
          color: '#C6DAED',
          fontSize: 16
        }
      },
      xAxis: {
        type: 'category',
        // nameGap: 5,
        axisTick: {
          show: false
        },
        nameTextStyle: {
          color: '#59B8F6',
          fontFamily: 'PingFangSC-Semibold, PingFang SC',
          fontSize: 12
        },
        boundaryGap: ['5%', '5%'],
        axisLine: {
          show: true,
          lineStyle: {
            color: '#3F9DDD',
            width: 2
          }
        },
        axisLabel: {
          fontSize: 12,
          fontFamily: 'TRENDS',
          color: '#59B8F6',
          margin: 20,
          rotate: 45,
          formatter: (value, index) => {
            return `${index + 1}: 00`
          }
        }
      },
      yAxis: [
        {
          name: 'KVA',
          splitLine: {
            show: true,
            lineStyle: {
              width: 2,
              color: '#0B6887',
              opacity: 0.5
            }
          },
          nameLocation: 'end',
          nameTextStyle: {
            color: '#59B8F6',
            fontFamily: 'SourceHanSansCN-Medium',
            fontSize: 12
          },
          axisTick: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              color: '#3F9DDD',
              width: 2,
              opacity: 0.5
            }
          },
          axisLabel: {
            fontSize: 12,
            fontFamily: 'TRENDS',
            color: '#59B8F6',
            margin: 20
          },
          type: 'value'
        },
        {
          name: '%',
          splitLine: { show: false },
          nameLocation: 'end',
          nameTextStyle: {
            color: '#59B8F6',
            fontFamily: 'SourceHanSansCN-Medium',
            fontSize: 12
          },
          axisTick: {
            show: false
          },
          axisLine: {
            show: true,
            lineStyle: {
              width: 2,
              color: '#3F9DDD',
              opacity: 0.5
            }
          },
          axisLabel: {
            fontSize: 12,
            fontFamily: 'TRENDS',
            color: '#59B8F6',
            margin: 20
          },
          type: 'value'
        }
      ],
      tooltip: {
        trigger: 'axis',
        backgroundColor: 'rgba(5, 21, 46, 0.7)',
        borderColor: '#2C679B',
        borderWidth: 2,
        textStyle: {
          color: '#fff'
        },
        position: function (point, params, dom, rect, size) {
          // 鼠标坐标和提示框位置的参考坐标系是:以外层div的左上角那一点为原点,x轴向右,y轴向下
          // 提示框位置
          var x = 0 // x坐标位置
          var y = 0 // y坐标位置
    ​
          // 当前鼠标位置
          var pointX = point[0]
          var pointY = point[1]
    ​
          // 外层div大小
          // var viewWidth = size.viewSize[0];
          // var viewHeight = size.viewSize[1];
    ​
          // 提示框大小
          var boxWidth = size.contentSize[0]
          var boxHeight = size.contentSize[1]
    ​
          // boxWidth > pointX 说明鼠标左边放不下提示框
          if (boxWidth > pointX) {
            x = 5
          } else {
            // 左边放的下
            x = pointX - boxWidth
          }
    ​
          // boxHeight > pointY 说明鼠标上边放不下提示框
          if (boxHeight > pointY) {
            y = 5
          } else {
            // 上边放得下
            y = pointY - boxHeight
          }
    ​
          return [x, y]
        }
      },
      series: [
        {
          name: '当日总视在功率',
          type: 'line',
          yAxisIndex: 1,
          areaStyle: {
            origin: 'start',
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [
                {
                  offset: 0,
                  color: `rgba(249, 214, 112, 1)` // 0% 处的颜色
                },
                {
                  offset: 0.5,
                  color: `rgba(249, 214, 112, 0.4)` // 0% 处的颜色
                },
                {
                  offset: 1,
                  color: `rgba(249, 214, 112, 0)` // 100% 处的颜色
                }
              ],
              global: false // 缺省为 false
            }
          },
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: 'line', // 默认为直线,可选为:'line' | 'shadow'
            lineStyle: {
              // 直线指示器样式设置
              color: '#cccccc',
              width: 2,
              type: 'solid'
            },
            shadowStyle: {
              // 阴影指示器样式设置
              width: 'auto', // 阴影大小
              color: 'rgba(150,150,150,0.3)' // 阴影颜色
            }
          },
          lineStyle: {
            color: `#F9D670`,
            shadowColor: 'white',
            shadowBlur: 0
          },
          showSymbol: true,
          itemStyle: {
            show: true,
            color: `rgba(249, 214, 112, 1)`
          },
          emphasis: {
            scale: true,
            itemStyle: {
              shadowBlur: 5,
              shadowColor: `#fff`
            }
          },
          data: transformerData.dayApparentPower
        },
        {
          name: '负载率',
          type: 'line',
          data: transformerData.dayLoadRate,
          areaStyle: {
            origin: 'start',
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 0,
              y2: 1,
              colorStops: [
                {
                  offset: 0,
                  color: `rgba(134, 231, 255, 1)` // 0% 处的颜色
                },
                {
                  offset: 0.5,
                  color: `rgba(134, 231, 255, 0.4)` // 0% 处的颜色
                },
                {
                  offset: 1,
                  color: `rgba(134, 231, 255, 0)` // 100% 处的颜色
                }
              ],
              global: false // 缺省为 false
            }
          },
          axisPointer: {
            // 坐标轴指示器,坐标轴触发有效
            type: 'line', // 默认为直线,可选为:'line' | 'shadow'
            lineStyle: {
              // 直线指示器样式设置
              color: '#cccccc',
              width: 2,
              type: 'solid'
            },
            shadowStyle: {
              // 阴影指示器样式设置
              width: 'auto', // 阴影大小
              color: 'rgba(150,150,150,0.3)' // 阴影颜色
            }
          },
          lineStyle: {
            color: `#86E7FF`,
            shadowColor: 'white',
            shadowBlur: 0
          },
          showSymbol: true,
          itemStyle: {
            show: true,
            color: `rgba(134, 231, 255, 1)`
          },
          emphasis: {
            scale: true,
            itemStyle: {
              shadowBlur: 5,
              shadowColor: `#fff`
            }
          }
        }
      ]
    }
    

1.4 分散折线图

  • 示例 分散折线图

  • option

    let xData = []
    for(let i = 0; i < 13; i++) {
        xData.push(2016 + i * 2)
    }
    let yDataA = [0, 60, 110, 280]
    let yDataa = ['', '', '', 280, 230, 210]
    let yDataB = [0, 50, 100, 140]
    let yDatab = ['', '', '', 140, 170, 200]
    let yDataC = [0, -50, -90, -100]
    let yDatac = ['', '', '', -100, -105, -120]
    for(let i = 0;i<7;i++) {
        yDataa.push(200 - i*15 - 10*Math.random())
        yDatab.push(200 + i*10 + 5*Math.random())
        yDatac.push(-120 - i*15 - 10*Math.random())
    }
    const option = {
        legend:{
            right: 30,
            top: 0,
            itemGap: 25,
            textStyle: {
                color: '#C6DAED',
                fontSize: 24
            }
        },
        grid: {
          left: 30,
          right: 30,
          top: '20%',
          bottom: 20,
          containLabel: true
        },
        xAxis: [
            {
                type: 'category',
                data: xData,
                axisLabel: {
    ​
                    fontSize: 24,
                    color: '#D0EDF4'
    ​
                }
            }
        ],
        yAxis: [
            {
                type: 'value',
                min: -300,
                max: 300,
                axisLabel: {
    ​
                    fontSize: 20,
                    color: '#D0EDF4'
    ​
                }
            }
        ],
        series:[
            {
                type: 'line',
                name: '碳中和',
                smooth: true,
                lineStyle: {
                    width: 4
                },
                data: yDataA
            },{
                type: 'line',
                name: '碳中和',
                smooth: true,
                lineStyle: {
                    type: 'dotted',
                    width: 4
                },
                markPoint: {
                    data: [{
                        name: '碳达峰',
                        symbol: 'diamond',
                        coord: [6,202],
                        symbolSize: 25,
                        itemStyle: {
                            color: '#7BE4FC'
                        },
                        label: {
                            show: true,
                            fontSize: 24,
                            positon: 'top',
                            formatter: '碳达峰',
                            color: '#7BE4FC',
                            offset: [20,-30]
                        }
                    }]
                },
                data: yDataa
            },{
                type: 'line',
                name: '碳排放',
                smooth: true,
                lineStyle: {
                    width: 4
                },
                data: yDataB
            },{
                type: 'line',
                name: '碳排放',
                smooth: true,
                lineStyle: {
                    width: 4,
                    type: 'dotted'
                },
                data: yDatab
            },{
                type: 'line',
                name: '碳减排',
                smooth: true,
                lineStyle: {
                    width: 4
                },
                data: yDataC
            },{
                type: 'line',
                name: '碳减排',
                smooth: true,
                lineStyle: {
                    width: 4,
                    type: 'dotted'
                },
                data: yDatac
            }
        ]
    }
    

1.5 动态评分仪表盘

  • 示例 vkRRyR.png

  • option

    const option = {
      series: [
        {
          type: 'gauge',
          center: ['50%', '50%'],
          startAngle: 180,
          endAngle: -180,
          min: 0,
          max: 100,
          splitNumber: 10,
          itemStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 0, color: 'rgba(84, 200, 239, 1)' },
              { offset: 0.5, color: 'rgba(4, 179, 238, 0.8000)' },
              { offset: 0.8, color: 'rgba(4, 179, 238, 0.3)' },
              { offset: 1, color: 'rgba(4, 179, 238, 0)' }
            ])
          },
          progress: {
            show: true,
            width: 0,
            overlap: false,
            roundCap: true,
            clip: false,
            itemStyle: {
              borderWidth: 3,
              borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(84, 200, 239, 1)' },
                { offset: 0.5, color: 'rgba(4, 179, 238, 0.8000)' },
                { offset: 0.8, color: 'rgba(4, 179, 238, 0.3)' },
                { offset: 1, color: 'rgba(4, 179, 238, 0.1)' }
              ])
            }
          },
          pointer: {
            show: false
          },
          axisLine: {
            lineStyle: {
              width: 0.5
            }
          },
          axisTick: {
            distance: -15,
            splitNumber: 5,
            lineStyle: {
              width: 1,
              color: 'rgba(4, 179, 238, 0.5)'
            }
          },
          splitLine: {
            distance: -17,
            length: 3,
            lineStyle: {
              width: 2,
              color: 'rgba(4, 179, 238, 0.5)'
            }
          },
          axisLabel: {
            show: false,
            distance: -20,
            color: '#999',
            fontSize: 20
          },
          anchor: {
            show: false
          },
          title: {
            show: false
          },
          detail: {
            show: false,
            valueAnimation: true,
            width: '60%',
            lineHeight: 40,
            borderRadius: 8,
            offsetCenter: [0, '-15%'],
            fontSize: 60,
            fontWeight: 'bolder',
            formatter: '{value} 分',
            color: 'auto'
          },
          data: [
            {
              value: 76
            }
          ]
        }
      ]
    }
    

1.6 渐变饼图

  • 示例 vkfVvd.png
  • option
  const pieData = {
    currentMonth: 0,
    categoryData: [
      {
        name: '分类1',
        value: 123
      },
      {
        name: '分类2',
        value: 34
      },
      {
        name: '分类3',
        value: 123
      },
      {
        name: '分类4',
        value: 86
      },
      {
        name: '分类5',
        value: 123
      }
    ]
  }

  pieData.currentMonth = pieData.categoryData.reduce((result, item) => result += item.value, 0)

  const option = {
    color: getColors(),
    title: {
      text: '当月自我核准减排',
      left: 30,
      top: -5,
      textStyle: {
        fontSize: 10,
        color: '#E5FAFA',
        fontFamily: 'TRENDS',
        shadowBlur: 7,
        shadowColor: 'rgba(95,248,250,0.6000)'
      }
    },
    legend: {
      orient: 'vertical',
      right: 0,
      top: 'center',
      icon: 'circle',
      itemWidth: 5,
      itemGap: 20,
      textStyle: {
        color: '#E5FAFA',
        fontSize: 9
      },
      formatter: (name) => {
        let value = pieData.categoryData.find((item) => item.name === name).value
        let perception = ((value / pieData.currentMonth) * 100 ).toFixed(2)
        return (
          ' ' + name + '  ' + perception + '%'
        )
      }
    },
    series: [
      {
        type: 'pie',
        z: 2,
        left: -60,
        top: 0,
        radius: ['40%', '50%'],
        avoidLabelOverlap: false,
        hoverAnimation: false,
        itemStyle: {
          borderRadius: 100,
          borderColor: 'rgba(0, 0, 0, 0)',
          borderWidth: 20
        },
        label: {
          show: true,
          formatter: `{b|当月}\n {a|${pieData.currentMonth}} \n {b|tCO₂} `,
          position: 'center',
          rich: {
            a: {
              fontSize: 14,
              color: '#E5FAFA',
              fontWeight: 500,
              fontFamily: 'OPPOSans-H',
              shadowColor: 'rgba(61,248,250,0.5200)',
              shadowBlur: 12,
              padding: [5, 0]
            },
            b: {
              fontSize: 7,
              color: '#E5FAFA'
            }
          }
        },
        emphasis: {
          scale: false
        },
        labelLine: {
          show: false
        },
        data: pieData.categoryData
      }
    ]
  }

  /**
   * 获取渐变颜色
   */
  const getColors = () => {
    let colors = ['3, 165, 221', '38, 213, 133', '246, 181, 0', '246, 136, 0', '250, 109, 51']
    let newColors = []

    colors.forEach((item) => {
      newColors.push(
        new echarts.graphic.LinearGradient(0, 0, 1, 1, [
          {
            offset: 0,
            color: `rgba(${item}, 1)`
          },
          {
            offset: 0.2,
            color: `rgba(${item}, 0.8)`
          },
          {
            offset: 0.4,
            color: `rgba(${item}, 0.5)`
          },
          {
            offset: 0.6,
            color: `rgba(${item}, 0.2)`
          },
          {
            offset: 0.8,
            color: `rgba(${item}, 0)`
          },
          {
            offset: 1,
            color: `rgba(${item}, 0)`
          }
        ])
      )
    })

    return newColors
  }

1.7 外边框饼图

  • 示例 vkffIK.png

  • option

    const deviceInfo = {
      total: 45,
      online: 45,
      outline: 0
    }
    let percentInfo = [
      +(props.dataInfo.online / props.dataInfo.total).toFixed(2),
      1 - (props.dataInfo.online / props.dataInfo.total).toFixed(2)
    ]
    
    const option = {
      backgroundColor: 'transparent',
      series: [
        {
          name: '数据',
          type: 'pie',
          startAngle: 315,
          right: '5%',
          z: 2,
          radius: ['40%', '70%'],
          // legendHoverLink: true,
          hoverAnimation: false,
          avoidLabelOverlap: false,
          labelLine: {
            length: 5,
            length2: 5,
            color: 'rgba(87, 202, 232, 0.8)',
            lineStyle: {
              cap: 'round'
            }
          },
          // labelLayout: (params) => {
          //   if (params.dataIndex === 1) {
          //     return {
          //       x: params.rect.x - 50,
          //       verticalAlign: 'middle',
          //       align: 'left'
          //     }
          //   } else if (params.dataIndex === 2) {
          //     return {
          //       x: params.rect.x + 60,
          //       y: params.rect.y + params.rect.height / 2,
          //       verticalAlign: 'middle',
          //       align: 'left'
          //     }
          //   }
          // },
          label: {
            formatter: (info) => {
              let res
    
              if (info.dataIndex === 0) {
                res = `{a|${deviceInfo.online}\n —— \n${deviceInfo.total}}`
              } else if (info.dataIndex === 1) {
                res = `{b|${info.data.name}}`
              } else {
                res = `{c|${info.data.name}}`
              }
    
              return res
            },
            rich: {
              a: {
                fontSize: 17,
                fontWeight: 600
              },
              b: {
                fontSize: 17,
                fontWeight: 600,
                color: 'rgba(62, 231, 150, 1)'
              },
              c: {
                fontSize: 17,
                fontWeight: 600,
                color: 'rgba(249, 110, 62, 1)'
              }
            }
          },
          data: [
            {
              value: 0.34,
              label: {
                position: 'center',
                color: '#fff',
                fontSize: 18
              },
              itemStyle: {
                normal: {
                  color: 'rgba(55,244,255,0)'
                }
              }
            },
            {
              value: percentInfo[0],
              name: percentInfo[0] * 100 + '%',
              itemStyle: {
                normal: {
                  color: {
                    type: 'linear',
                    x: 0,
                    y: 0,
                    x2: 0,
                    y2: 1,
                    colorStops: [
                      {
                        offset: 0,
                        color: '#57cbe9' // 0% 处的颜色
                      },
                      {
                        offset: 1,
                        color: 'rgba(34, 68, 96, 0.4)' // 100% 处的颜色
                      }
                    ],
                    global: false // 缺省为 false
                  }
                }
              }
            },
            {
              value: percentInfo[1],
              name: parseInt(percentInfo[1] * 100) + '%',
              itemStyle: {
                normal: {
                  color: 'rgba(36, 88, 118, 0.5)'
                }
              }
            }
          ]
        },
        {
          name: '外边框',
          type: 'pie',
          startAngle: 227,
          z: 1,
          clockWise: false,
          radius: ['30%', '80%'], //边框大小
          center: ['47%', '50%'], //边框位置
          hoverAnimation: false,
          avoidLabelOverlap: false,
          label: {
            show: false
          },
          data: [
            {
              value: 3,
              label: {
                position: 'center',
                color: '#fff',
                fontSize: 18
              },
              itemStyle: {
                normal: {
                  color: 'rgba(55,244,255,0)'
                }
              }
            },
            {
              value: 10,
              label: {
                show: false
              },
              labelLine: {
                show: false
              },
              itemStyle: {
                normal: {
                  color: 'rgb(9,37,71, 0.1)',
                  global: false, // 缺省为 false
                  borderRadius: 0,
                  borderWidth: 1, //设置边框粗细
                  borderColor: 'rgba(88, 205, 233, 0.5)' //边框颜色
                }
              }
            }
          ]
        }
      ]
    }
    

1.8 分离饼图

  • 示例 vkhkd0.png
  • option
const evalInfo = {
  data: [43, 18, 14, 16]
}
​
const option = {
  title: {
    text: '综合动态评价',
    textStyle: {
      color: '#D1EAEA',
      fontSize: 16,
      fontFamily: 'TRENDS'
    }
  },
  color: [
    'rgb(111, 211, 246)',
    'rgb(50, 214, 134)',
    'rgb(254, 209, 82)',
    'rgb(254, 174, 72)'
  ],
  legend: {
    show: false,
    orient: 'vertical',
    padding: 5,
    right: '5%',
    top: 'center',
    icon: 'circle',
    textStyle: {
      color: '#fff'
    }
  },
  series: [
    {
      type: 'pie',
      z: 2,
      radius: ['60%', '70%'],
      top: '10%',
      avoidLabelOverlap: false,
      hoverAnimation: false,
      itemStyle: {
        borderRadius: 100,
        borderColor: 'rgb(2, 29, 65, 1)',
        borderWidth: 5
      },
      label: {
        show: true,
        formatter: (param) => {
          let types = ['能源应用', '环境健康', '舒适宜居', '物业管理']
          return `{a|${types[param.dataIndex]} }{${['b', 'c', 'd', 'e'][param.dataIndex]}|${
            evalInfo.data[param.dataIndex]
          }分}`
        },
        // position: 'center',
        rich: {
          a: {
            fontSize: 14,
            fontFamily: 'TRENDS',
            color: '#D1EAEA'
          },
          b: {
            fontSize: 20,
            fontFamily: 'DINAlternate-Bold',
            color: '#00C6FC'
          },
          c: {
            fontSize: 20,
            fontFamily: 'DINAlternate-Bold',
            color: '#39B979'
          },
          d: {
            fontSize: 20,
            fontFamily: 'DINAlternate-Bold',
            color: '#EC8017'
          },
          e: {
            fontSize: 20,
            fontFamily: 'DINAlternate-Bold',
            color: '#F5BE13'
          }
        }
      },
      emphasis: {
        scale: false
      },
      labelLine: {
        length: 20,
        length2: 20,
        show: true
      },
      data: [
        { value: evalInfo.data[0], name: '环境健康' },
        { value: evalInfo.data[1], name: '舒适宜居' },
        { value: evalInfo.data[2], name: '能源应用' },
        { value: evalInfo.data[3], name: '物业管理' }
      ]
    },
    {
      name: '外边框',
      type: 'pie',
      z: 1,
      clockWise: false,
      radius: ['48%', '75%'], //边框大小
      center: ['50%', '55%'], //边框位置
      hoverAnimation: false,
      avoidLabelOverlap: false,
      data: [
        {
          value: 10,
          label: {
            show: false
          },
          labelLine: {
            show: false
          },
          itemStyle: {
            normal: {
              color: 'rgb(9,37,71, 0)',
              global: false, // 缺省为 false
              borderRadius: 0,
              borderWidth: 1, //设置边框粗细
              borderColor: 'rgba(88, 205, 233, 0.8)' //边框颜色
            }
          }
        }
      ]
    }
  ]
}

1.9 金字塔图(highcharts)

  • 示例 v8aCkR.png

  • 配置

    import Highcharts from 'highcharts/highstock'
    import HighchartsMore from 'highcharts/highcharts-more'
    import HighchartsDrilldown from 'highcharts/modules/drilldown'
    import Highcharts3D from 'highcharts/highcharts-3d'HighchartsMore(Highcharts)
    HighchartsDrilldown(Highcharts)
    Highcharts3D(Highcharts)
    ​
    const getColors = () => {
      // console.log(Highcharts.Color('#d5a71d'))
      const colors = ['#d5a71d', '#da8f2d', '#24c878', '#60c1f2']
      let mycolors = Highcharts.map(colors, function (color) {
        return {
          radialGradient: { cx: 0.5, cy: 0.3, r: 0.7 },
          stops: [
            [0, color],
            [0.6, Highcharts.Color(color).setOpacity(0.8).get('rgba')],
            [1, Highcharts.Color(color).setOpacity(0.2).get('rgba')] // darken
          ]
        }
      })
      return mycolors
    }
    ​
    Highcharts.chart('evalChart', {
      credits: {
        enabled: false
      },
      chart: {
        type: 'columnpyramid',
        backgroundColor: 'transparent'
      },
      title: {
        text: null
      },
      colors: getColors(),
      xAxis: {
        crosshair: true,
        lineColor: '#3a627f',
        labels: {
          style: {
            color: 'rgba(187, 228, 255, 1)',
            fontSize: '10px'
          }
        },
        type: 'category',
        categories: ['名字1', '名字2', '3', '4']
      },
      yAxis: {
        min: 0,
        lineWidth: 1,
        lineColor: '#3a627f',
        title: {
          text: '分',
          enabled: false,
          align: 'high',
          // x: 20,
          // y: -10,
          rotation: 0,
          style: {
            color: '#246591'
          }
        },
        gridLineWidth: 0,
        tickInterval: 25,
        labels: {
          style: {
            color: '#246591'
          }
        }
      },
      tooltip: {
        enabled: false
      },
      plotOptions: {
        series: {
          borderWidth: 0,
          dataLabels: {
            enabled: true,
            color: '#fff',
            style: {
              fontWeight: 'bold',
              textOutline: 'none'
            }
            // shadow: false
          }
        }
      },
      series: [
        {
          name: '分数',
          colorByPoint: true,
          data: [10, 32, 43, 14],
          showInLegend: false
        }
      ]
    })
    ​
    

2. echarts组件封装

<template>
  <div
    class="echart-comp-box"
    ref="chartDom"
    :style="{
      width: typeof ewidth === 'string' ? ewidth : ewidth + '%',
      height: typeof eheight === 'string' ? eheight : eheight + '%'
    }"
  ></div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, defineProps, watch, nextTick } from 'vue'
import * as echarts from 'echarts'//获取 dom 和 父组件数据 并定义"myChart"用于初始化图表
const chartDom = ref()
let myChart = nullconst props = defineProps({
  option: Object,
  ewidth: [Number, String], // 容器宽度, 字符串直接展示, 数字类型为%展示
  eheight: [Number, String] // 容器高度
})
​
//监听图表数据时候变化,重新渲染图表
watch(
  () => props.option,
  (newV) => {
    if (myChart) {
      myChart.setOption(props.option, true)
    } else {
      initChart()
    }
  },
  { deep: true }
)
​
//重绘图表函数
const resizeHandler = () => {
  myChart.resize()
}
​
//设置防抖,保证无论拖动窗口大小,只执行一次获取浏览器宽高的方法
const debounce = (fun, delay) => {
  let timer
  return function () {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fun()
    }, delay)
  }
}
​
const cancalDebounce = debounce(resizeHandler, 500)
​
//页面成功渲染,开始绘制图表
onMounted(() => {
  initChart()
})
const initChart = () => {
  if (chartDom.value) {
    chartDom.value.setAttribute('_echarts_instance_', '')
    // 配置为 svg 形式,预防页面缩放而出现模糊问题;图表过于复杂时建议使用 Canvas
    myChart = echarts.init(chartDom.value, null, { renderer: 'svg' })
    // myChart = echarts.init(chartDom.value)
    props.option && myChart.setOption(props.option, true)
    // 自适应不同屏幕时改变图表尺寸
    window.addEventListener('resize', cancalDebounce)
  }
}
//页面销毁前,销毁事件和实例
onBeforeUnmount(() => {
  window.removeEventListener('resize', cancalDebounce)
  myChart?.dispose()
})
</script>
<style lang="scss" scoped>
.echart-comp-box {
  width: 100%;
  height: 100%;
}
</style>

3. 其它案例资源