You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Echarts自定义仪表盘标签定位问题

Apache Echarts自定义仪表盘标签定位问题

看起来你已经把仪表盘的基础样式搭得有模有样了!现在要实现刻度上下两组标签(等级+百分比区间)的布局,这个需求在ECharts里完全可以搞定,我给你两种可行的方案,结合你的代码来调整:

先对比下你的当前效果和预期效果:

已实现效果预期效果
已实现的仪表盘预期的仪表盘

方案一:用Graphic组件添加独立的第二组标签(推荐,定位更灵活)

这个方案通过ECharts的graphic文本组件,在原有等级标签下方添加百分比区间标签,能精确控制每组标签的位置和样式。

修改后的完整代码如下,关键修改处我都标出来了:

import { Component } from '@angular/core';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';
import * as echarts from 'echarts/core';
import { GaugeChart } from 'echarts/charts';
// 1. 新增GraphicComponent的导入
import { GridComponent, GraphicComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';

// 2. 注册GraphicComponent到ECharts
echarts.use([GaugeChart, GridComponent, GraphicComponent, CanvasRenderer]);

@Component({
  selector: 'app-gauge',
  standalone: true,
  imports: [NgxEchartsModule],
  templateUrl: './gauge.component.html',
  styleUrls: ['./gauge.component.scss'],
  providers: [
    { provide: NGX_ECHARTS_CONFIG, useValue: { echarts } }
  ]
})
export class GaugeComponent {
  chartOptions = {
    series: [
      {
        type: 'gauge',
        startAngle: 180,
        endAngle: 0,
        center: ['50%', '75%'],
        radius: '90%',
        min: 0,
        max: 1,
        splitNumber: 8,
        axisLine: {
          lineStyle: {
            width: 20,
            color: [
              [0.125, '#FC0202FF'],
              [0.250, '#A15D39FF'],
              [0.375, '#F8C187FF'],
              [0.500, '#F5FF6EAF'],
              [0.625, '#A8FF6EFF'],
              [0.750, '#60FD72FF'],
              [0.875, '#2FCE77FF'],
              [1,     '#16852EFF']
            ]
          }
        },
        pointer: {
          icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
          length: '12%',
          width: 25,
          offsetCenter: [0, '-60%'],
          itemStyle: {
            color: 'auto'
          }
        },
        axisTick: {
          length: 12,
          lineStyle: {
            color: 'auto',
            width: 2
          }
        },
        splitLine: {
          // 3. 修正拼写错误:lenth → length
          length:20,
          lineStyle: {
            color: 'auto',
            width: 5
          }
        },
        axisLabel: {
          color: '#464646',
          fontSize: 15,
          // 4. 调整distance让等级标签更靠近刻度上方
          distance: -20,
          rotate: 'tangential',
          formatter: function (value: number) {
            if (value >= 0.875 && value <= 1.00) {
              return 'AAA';
            } else if (value === 0.875) {
                return 'AA';
            } else if (value === 0.750) {
                return 'A';
            } else if (value === 0.625) {
                return 'BBB';
            } else if (value === 0.500) {
              return 'BB';
            } else if (value === 0.375) {
              return 'B';
            } else if (value === 0.250) {
              return 'C';
          }  else if (value >= 0.00 && value < 0.125) {
            return 'D';
          }
          return '';
          }
        },
        title: {
          offsetCenter: [0, '-10%'],
          fontSize: 20
        },
        detail: {
          fontSize: 30,
          offsetCenter: [0, '-30%'],
          valueAnimation: true,
          formatter: function (value: number) {
            return Math.round(value * 100) + '';
          },
          color: 'inherit'
        },
        data: [
          {
            value: 0.9,
            name: 'Grade Rating'
          }
        ]
      }
    ],
    // 5. 新增graphic配置,添加下方的百分比区间标签
    graphic: [
      // 每个标签对应仪表盘的一个刻度,通过三角函数计算弧形位置
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '90-100', fontSize: 12, color: '#464646' },
        rotation: 0,
        position: [Math.cos(0) * 220, Math.sin(0) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '80-90', fontSize: 12, color: '#464646' },
        rotation: Math.PI / 8,
        position: [Math.cos(Math.PI / 8) * 220, Math.sin(Math.PI / 8) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '70-80', fontSize: 12, color: '#464646' },
        rotation: Math.PI / 4,
        position: [Math.cos(Math.PI / 4) * 220, Math.sin(Math.PI / 4) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '60-70', fontSize: 12, color: '#464646' },
        rotation: 3 * Math.PI / 8,
        position: [Math.cos(3 * Math.PI / 8) * 220, Math.sin(3 * Math.PI / 8) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '50-60', fontSize: 12, color: '#464646' },
        rotation: Math.PI / 2,
        position: [Math.cos(Math.PI / 2) * 220, Math.sin(Math.PI / 2) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '40-50', fontSize: 12, color: '#464646' },
        rotation: 5 * Math.PI / 8,
        position: [Math.cos(5 * Math.PI / 8) * 220, Math.sin(5 * Math.PI / 8) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '30-40', fontSize: 12, color: '#464646' },
        rotation: 3 * Math.PI / 4,
        position: [Math.cos(3 * Math.PI / 4) * 220, Math.sin(3 * Math.PI / 4) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '20-30', fontSize: 12, color: '#464646' },
        rotation: 7 * Math.PI / 8,
        position: [Math.cos(7 * Math.PI / 8) * 220, Math.sin(7 * Math.PI / 8) * 220]
      },
      {
        type: 'text',
        left: 'center',
        top: '65%',
        style: { text: '0-20', fontSize: 12, color: '#464646' },
        rotation: Math.PI,
        position: [Math.cos(Math.PI) * 220, Math.sin(Math.PI) * 220]
      }
    ]
  };
}

关键调整说明:

  • 注册了GraphicComponent,用来添加额外的文本标签;
  • 修正了splitLine的拼写错误,避免样式不生效;
  • 调整axisLabel的distance,让等级标签位置更合理;
  • 通过三角函数计算每个百分比标签的弧形位置和旋转角度,完美匹配仪表盘的弧度;
  • 你可以根据实际需求调整graphic里的fontSize、position偏移值,让标签位置更精准。

方案二:用AxisLabel的Formatter实现换行标签(更简洁)

如果觉得添加graphic组件太繁琐,也可以直接在axisLabel的formatter里返回换行的文本,让每个标签显示两行内容:

axisLabel: {
  color: '#464646',
  fontSize: 12,
  distance: -35, // 调整这个值让两行内容都显示在合适位置
  rotate: 'tangential',
  formatter: function (value: number) {
    let grade = '';
    let range = '';
    if (value >= 0.875 && value <= 1.00) {
      grade = 'AAA';
      range = '90-100';
    } else if (value === 0.875) {
      grade = 'AA';
      range = '80-90';
    } else if (value === 0.750) {
      grade = 'A';
      range = '70-80';
    } else if (value === 0.625) {
      grade = 'BBB';
      range = '60-70';
    } else if (value === 0.500) {
      grade = 'BB';
      range = '50-60';
    } else if (value === 0.375) {
      grade = 'B';
      range = '40-50';
    } else if (value === 0.250) {
      grade = 'C';
      range = '20-30';
    } else if (value >= 0.00 && value < 0.125) {
      grade = 'D';
      range = '0-20';
    }
    return [grade, range].join('\n'); // 用换行符实现两行标签
  }
}

这种方式代码更简洁,但需要反复调整distance和fontSize来让两行内容都显示在合适的弧形位置上。


你可以根据自己的需求选择其中一种方案,希望能帮你搞定这个布局问题!

备注:内容来源于stack exchange,提问作者Evangelos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 20:19:33