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
相关产品推荐
相关产品推荐



