做数据可视化这些年,ECharts 里最让我觉得“既简单又反直觉”的配置,就是坐标轴的 name。明明只是给 x 轴、y 轴加一行说明文字,默认位置却总是出人意料:y 轴名称跑到轴线正上方,x 轴名称贴在刻度起始端,想让它垂直居中在轴线左侧,翻配置试了十几次才找到正确写法。如果你也被 x 轴、y 轴 name 的位置调整折腾过,这篇文章应该能帮你省下不少时间。我会把 ECharts 中坐标轴 name 的完整控制逻辑拆开讲清楚,包括配置项的作用、默认行为复盘、高频场景的完整示例,以及几个很容易踩进去却不自知的坑。
1. 先把 name 的四大配置项拆开:location、gap、rotate、textStyle 说了算
很多初学者以为“name 位置”只有一个配置项,找不到就直接改字号、加空格硬顶。实际上 ECharts 对坐标轴 name 有一套独立配置,只要理解这几个字段,位置调整就是加减法问题。
1.1 nameLocation:决定 name 挂在轴线的哪一段
官方给出的可选值只有三个:start、middle、end,分别对应轴线的最开始、正中间、最末端。这里先记住一个关键结论:x 轴和 y 轴的默认值都是end,但视觉上完全不同——x 轴的end是右下角,y 轴的end是正上方。
option = { xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五'], name: '星期', nameLocation: 'end' // x轴默认就是end,显示在轴线右端 }, yAxis: { type: 'value', name: '数值', nameLocation: 'end' // y轴也是end,显示在y轴顶端 }, series: [{ type: 'line', data: [120, 200, 150, 80, 70] }] };实际项目中,我们会把 y 轴的nameLocation改成middle,再配一个旋转角度,让它变成刻度左侧常见的竖排文字。x 轴则经常改成middle,让名称居中显示在横轴下方,这些组合写法我放到第 3 节细说,这里先把语义记住:start是“轴线这头”,middle是“轴线正中”,end是“轴线那头”。
提示:
nameLocation控制的只是 name 总体在轴线上的方位,它不会自动帮你计算“文本会不会超出画布”,所以经常出现“配置对了但名字被裁掉一半”的情况,这个问题后面单独讲。
1.2 nameGap:name 到轴线之间到底隔着多少像素
nameGap是英文“name gap”的意思,单位固定为像素,默认值是15。它表示 name 文本与坐标轴线之间的距离。需要注意一个细节:这个距离的基准点不是“文本边缘”,而是 ECharts 内部计算出的 name 文本定位锚点,锚点和文本自身样式有关,所以当你加大字号或换行后,肉眼看到的实际间隙会和预期有偏差。
yAxis: { name: '产值(万元)', nameLocation: 'middle', nameGap: 40, // 从默认15加大到40,让name离轴线更远 nameRotate: 90 }这个字段是“位置微调”里最实用的。比如默认时 name 紧贴刻度,看着很局促,你只需要把nameGap从 15 加到 35 或 40,立刻就会舒服很多。它和grid边距是两套体系,不要混在一起调。
1.3 nameRotate 与 nameTextStyle:文本方向、字号、颜色一次配齐
nameRotate是 name 文本的旋转角度,单位为度,默认0。这里有个经常被吐槽的点:很多人想旋转 y 轴 name,第一反应是去nameTextStyle里找rotate,结果翻遍文档没找到。ECharts 里刻度标签的旋转在axisLabel.rotate,而轴名称的旋转叫nameRotate,它和nameTextStyle是平级关系。
yAxis: { name: '降雨量 (mm)', nameLocation: 'middle', nameGap: 45, nameRotate: 90, // 关键:让name旋转90度,变竖排 nameTextStyle: { fontSize: 14, color: '#16557A', fontWeight: 'bold' } }nameTextStyle支持常规的color、fontSize、fontWeight、fontFamily,也支持align和verticalAlign。不过当nameRotate非 0 时,对齐方式会交互作用,建议以实际渲染效果为准,不要凭直觉猜。这种“配置字段命名不统一”的情况在 ECharts 里不算少见,也是很多人调 name 位置时觉得混乱的根源。
| 配置项 | 作用 | 默认值 | 备注 |
|---|---|---|---|
name | 轴名称文本内容 | 无 | 支持\n换行和 rich 模板 |
nameLocation | 名称在轴线上的方位 | end | 可选start/middle/end |
nameGap | 名称与轴线的间距 | 15 | 单位为像素 |
nameRotate | 名称文本旋转角度 | 0 | 与刻度标签的axisLabel.rotate不是同一个 |
nameTextStyle | 字号、颜色、对齐方式 | 随主题 | 新版支持 rich、width、overflow |
2. 默认行为复盘:为什么第一次总是调不对位置
这一节咱们不做操作,先看 ECharts 默认渲染到底发生了什么。理解了默认行为,后面所有“调整”都会变得顺理成章。
2.1 x 轴默认 end、y 轴默认 end,但视觉上“一个在右下、一个在左上”
先看一个最小配置,不写任何 name 相关字段,只给 x 轴、y 轴定义name。渲染结果大致是:x 轴名称显示在横轴最右端,紧贴右下角;y 轴名称显示在纵轴最上端,也就是左上角附近。
为什么同样都是end,视觉感受差别这么大?因为直角坐标系里 x 轴的增长方向是从左到右,y 轴的增长方向是从下到上,而end永远指向“轴线的终点方向”。x 轴的终点是右端,y 轴的终点是顶端。这个语义很符合数学直觉,但对第一次用 ECharts 的人来说,往往以为 name 会显示在“轴线的外侧统一位置”,结果就懵了。
2.2 类目轴与数值轴上 name 的呈现差异
ECharts 的 x 轴、y 轴都有轴类型(type),常见的是category(类目轴)和value(数值轴)。这两类轴上的 name 默认位置基本一致,但在“数值范围不同”时会有感知差别。
类目轴没有实际比例尺,刻度和分类数量绑定,所以end位置固定是最后一个分类旁边;数值轴有刻度区间,end固定是最大值位置。当你把数值轴的最大值调大,比如从 100 改到 1000,end位置的 name 会跟着轴线端点一起挪到更高的位置,但和刻度标签的相对位置不会变。
yAxis: { type: 'value', max: 1000, // 修改max后,name在end位置时也跟随移动 name: '温度 (°C)', nameLocation: 'end' }这个规律在“动态切换数据范围”的项目里很重要。比如一个监控图表,某段时间数据峰值很高,max自动扩增,name 跟着顶部跑,视觉上就不太稳定。遇到这种场景,我更推荐把 y 轴 name 固定到middle位置,再配合nameRotate: 90,无论数据高低,名称都稳定在轴中间,观感会好很多。
2.3 inverse 轴会让 start/end 的语义颠倒
还有一个容易被忽略的配置:inverse。当坐标轴开启了inverse: true,坐标轴方向会反转,比如 y 轴从下往上变成从上往下,x 轴从右向左。这时start和end的指向也会跟着反转。
xAxis: { type: 'value', inverse: true, name: '深度 (m)', nameLocation: 'start' // inverse后,start指向视觉上的右端 }我见过有人写层析数据图时,纵轴深度方向反转,name 突然从预期的上方跑到了下方,排查到最后才发现是inverse在起作用。所以当 name 位置“莫名其妙”不对时,先看一眼坐标轴有没有开启反向,别急着怀疑配置写错。
3. 高频场景实操:x 轴、y 轴 name 定位的完整配置示例
接下来是这篇博文最核心的部分。我整理了四个真实项目里频率最高的 name 位置需求,每个都给出可直接抄写的配置和调整思路。
3.1 场景一:y 轴名称垂直居中在轴线左侧
这是折线图、柱状图里最常见的需求,也就是让 y 轴单位名称竖着显示在纵轴左侧中间。标准写法如下:
option = { grid: { left: 70, // 为y轴name留出空间 right: 30, top: 40, bottom: 40 }, yAxis: { type: 'value', name: '销售额(万元)', nameLocation: 'middle', nameGap: 40, nameRotate: 90, nameTextStyle: { fontSize: 14, color: '#333' } }, xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月'] }, series: [ { type: 'bar', data: [120, 200, 150, 80, 170] } ] };这里三个字段缺一不可:nameLocation: 'middle'让 name 在 y 轴纵向中点附近;nameRotate: 90让文本旋转成竖排;nameGap: 40让文本和轴线拉开距离,避免文字贴住刻度。调nameGap时可以按这个经验值起步:中文字体 14px 时,nameGap40 到 55 之间视觉都比较舒服;如果是英文长单词或带括号的字符串,比如Sales (Unit: Million),建议直接加到 60 以上。
提示:
grid.left要保证足够宽,否则 y 轴 name 会被画布裁掉。判断标准很简单:grid.left约等于nameGap + name文本最大宽度 + axisLabel预留宽度,拿不准就先用 80,再逐步缩小。
3.2 场景二:x 轴名称居中、靠左、靠右怎么摆
x 轴 name 的调整没有旋转需求,主要是位置切换。
- 居中放在横轴正下方:
nameLocation: 'middle',nameGap: 20左右。 - 靠左放在起始端:
nameLocation: 'start',适合强调“从这一刻开始”的语义。 - 靠右放在末端:保持默认
end即可。
xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'], name: '季度', nameLocation: 'middle', // 改成start或end即可切换位置 nameGap: 25, nameTextStyle: { fontSize: 13 } }这里想提醒一个容易忽略的兼容问题:当 x 轴刻度标签很长且开启旋转后,比如日期格式2024-11-11 08:00:00,axisLabel.rotate设为 30 度或 45 度,标签会向下伸展。此时如果 x 轴 name 还是end,它会落在右下角,和旋转后的刻度标签挤在一起,视觉非常乱。我的做法是:日期类长标签的图表,x 轴 name 统一用nameLocation: 'middle',让名称离开角落,减少和旋转标签的冲突。
3.3 场景三:双 y 轴分别控制左右两侧 name
双 y 轴(双纵轴)在混合图表里非常常见,比如左侧画柱状图表示销售额,右侧画折线图表示增长率。此时yAxis是一个数组,每一项对应一个独立的坐标轴,name 配置也完全独立。
option = { legend: { data: ['销售额', '增长率'], top: 10 }, grid: { left: 60, right: 60, top: 40, bottom: 40 }, xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五'] }, yAxis: [ { type: 'value', name: '销售额(万元)', nameLocation: 'middle', nameGap: 40, nameRotate: 90 }, { type: 'value', name: '增长率(%)', nameLocation: 'middle', nameGap: 40, nameRotate: -90, // 右侧轴name旋转-90度,文字从下往上读 splitLine: { show: false } } ], series: [ { name: '销售额', type: 'bar', yAxisIndex: 0, data: [120, 200, 150, 80, 170] }, { name: '增长率', type: 'line', yAxisIndex: 1, data: [5, 12, 8, 3, 9] } ] };这里有一个细节值得单独说:右侧 y 轴的nameRotate我用了-90,而不是90。两个角度渲染出来都是竖排,但文本方向相反。90时文字顺时针旋转,适合左侧轴;-90时逆时针旋转,适合右侧轴。如果左右都用90,右侧的文字头部会朝右,阅读习惯上很别扭。这个问题在网上被问了无数遍,答案其实就是正负号的选择。
双 y 轴还有另一个长期痛点:右侧 y 轴 name 默认end时会顶到图表右上角,经常和 legend 重叠。我建议双轴场景下,两个 y 轴都改用middle+ 正负 90 度旋转,把顶部空间让给图例,视觉重心也更稳定。
3.4 场景四:多 grid 情况下每个坐标轴的 name 独立配置
当页面里有多个网格(多图表排版),比如上边一个柱状图、下边一个折线图,每个 grid 有自己的 x 轴、y 轴。此时坐标轴要通过gridIndex关联到具体的 grid,name 配置同样各自独立。
option = { grid: [ { left: 70, top: 30, width: '80%', height: '35%' }, { left: 70, bottom: 40, width: '80%', height: '35%' } ], xAxis: [ { type: 'category', gridIndex: 0, data: ['A', 'B', 'C'], name: '月份', nameLocation: 'middle' }, { type: 'category', gridIndex: 1, data: ['X', 'Y', 'Z'], name: '季度', nameLocation: 'middle' } ], yAxis: [ { type: 'value', gridIndex: 0, name: '产量', nameLocation: 'middle', nameGap: 40, nameRotate: 90 }, { type: 'value', gridIndex: 1, name: '销量', nameLocation: 'middle', nameGap: 40, nameRotate: 90 } ], series: [ { type: 'bar', xAxisIndex: 0, yAxisIndex: 0, data: [10, 20, 15] }, { type: 'line', xAxisIndex: 1, yAxisIndex: 1, data: [8, 12, 6] } ] };这里最常见的错误是:只写一个 xAxis 和 yAxis,却想控制两个网格,结果 name 全部挤到第一个 grid 上。记住,多 grid 场景里,xAxis、yAxis 都要声明成数组,个数和 grid 对应,并通过gridIndex绑定归属。name 的nameLocation、nameGap在每个数组元素里分别配置,互不干扰。
4. 常见翻车现场与排查链路
这一节写的是我实际踩过、也帮同事排查过的几个“翻车”案例。它们不像配置写错那样明显报错,但效果就是不对,网上提问的人非常多。
4.1 name 写进 axisName 里不生效
有个高频低级错误:把轴名称写到xAxis.axisName或yAxis.axisName。ECharts 坐标轴配置里根本没有axisName这个字段,正确字段就是第一层级的name。写错后不报错也不警告,只是图表里什么都不显示,很多人会陷入“是不是颜色不对、字号不对”的排查循环。
// 错误示范:字段名不存在,图表不报错但不显示 xAxis: { type: 'category', axisName: '时间' // 无效 } // 正确写法 xAxis: { type: 'category', name: '时间' }排查建议带着这个思路:图表里任何“应该有但没有”的东西,先看字段名是不是拼写错误或放错了层级。这种问题用控制台console.log(option)核对未必能发现,最有效的方式是直接对照官方文档的字段树。
4.2 name 被吞:grid 边距不够导致的截断
第二个高频问题是 name 被画布截断。典型表现是:y 轴名称只露出半个“销”字,或者 x 轴名称在右下角看不到完整字符串,但你加大nameGap也没用。
原因在grid。网格区域占用了绘图区的绝大部分空间,而 name 是绘制在网格区域之外的。当grid.left、grid.right、grid.top、grid.bottom太小,name 所在的“外挂区域”被压缩到画布边缘以外,就会被直接裁掉。canvas 渲染器下不会报任何错误,也不会干涉图表内部布局。
我的排查链路是:
- 先临时把
grid的四周边距全部调大,比如left: 80, right: 80, top: 80, bottom: 80,确认 name 是否完整出现。 - 如果出现了,逐步缩小边距,找到“刚好完整”的临界值。
- 给临界值加上安全余量,通常加 8 到 15px,作为最终值。
grid: { left: 80, // 临时调大,确认就是边距问题 right: 30, top: 50, bottom: 40 }这个方法不仅能解决 name 截断,还能顺带确认图例、刻度标签的空间占用,算是一个通用的诊断技巧。
4.3 name 与刻度标签重叠:nameGap 和 axisLabel.margin 怎么配合
第三个问题是 name 和刻度标签挤在一起。比如 y 轴左侧,nameRotate: 90后 name 竖排,但和120、200之类的刻度数字贴得太近;或者 x 轴下方,name 和1月、2月挤成一团。
原因是nameGap和axisLabel.margin共同决定“name 与刻度”之间的距离,而很多人只调了其中一个。axisLabel.margin控制刻度文本与轴线之间的距离,默认 8px;nameGap控制 name 锚点与轴线之间的距离。两者叠加后才是 name 与刻度的实际视觉距离。
yAxis: { type: 'value', name: '浓度 (mg/L)', nameLocation: 'middle', nameGap: 50, // 调大这个名字间距 nameRotate: 90, axisLabel: { margin: 12 // 同时调大刻度标签与轴线的间距 } }当 name 和刻度仍显拥挤时,先不动nameGap,试着把axisLabel.margin从默认 8 增加到 10 或 12。这样刻度数字会整体右移,name 和刻度数字之间的空隙会明显改善。反过来,如果网格区域空间有限,也可以缩小nameGap并给grid.left留出足够余量,用网格边距换空间,而不是一味叠加间距。
4.4 name 与图例抢位置:优先调整 grid 还是 nameLocation
第四个问题集中在“右上角冲突”。当图例默认放置在顶部,y 轴 name 又是end位置时,两个文本会同时出现在左上到右上的区域,视觉上互相挤压。双 y 轴图表中,右侧轴的 name 更容易和图例打架。
我建议的优先级是:先考虑改变nameLocation,再考虑移动图例,最后才动grid。因为图例承载的信息更多,用户需要通过它识别系列,优先级应该高于轴名称。具体操作:把冲突的 y 轴nameLocation从end改为middle,并配合nameRotate: 90/-90,让轴名称让出顶部空间。如果两个 y 轴都改完顶部还是挤,再把legend的top往下挪一两个像素,或者直接放到图表底部。
legend: { data: ['销量', '增长率'], top: 10 // 如果顶部被占用,可改成 bottom: 10 }需要强调:网格的grid.top默认会给图例预留空间,但预留量并不总能覆盖自定义 name 的占用。因此文本类元素冲突时,先从文本自身的位置配置入手,是最快、副作用最小的路径。
5. 进阶技巧与个人建议
最后这部分,我分享几个项目实战中沉淀下来的技巧,不一定写在官方文档里,但能减少很多返工。
5.1 用 nameTextStyle.rich 让轴名称支持多格式
nameTextStyle支持rich富文本,意味着你可以让“名称主体”和“单位”使用不同字号、颜色,不需要把单位硬塞进字符串里一起变样式。
yAxis: { name: '{title|降雨量}\n{unit|(mm)}', nameLocation: 'middle', nameGap: 50, nameRotate: 90, nameTextStyle: { rich: { title: { fontSize: 15, color: '#333', fontWeight: 'bold' }, unit: { fontSize: 12, color: '#999' } } } }需要注意,name里的\n换行在旋转后可能表现得很“陡峭”,不同版本的 ECharts 对 long text + rich 的布局算法有细微差异。如果你用 5.2 以下版本,nameTextStyle里的width、overflow属性不一定生效,换行只能靠字符串里的\n;5.2 以上版本则可以直接给 nameTextStyle 设置width和overflow: 'break',对长单位文本更友好。
5.2 name 的响应式与 resize 适配
大屏项目里,图表的容器尺寸会随窗口变化,name 的位置用固定像素值虽然方便,但窄屏时很容易再次出现截断。我的经验是:把grid边距写成百分比,把nameGap和字号结合动态计算。
const nameFontSize = 14; const yName = '累计成交额'; const yNameGap = Math.max(40, yName.length * nameFontSize / 2 + 20); option.yAxis.nameGap = yNameGap; option.grid.left = yNameGap + nameFontSize * 2;这个公式的思路是:name 旋转成竖排后,横向占用的空间约等于字号乘以字符数的一半,再加上一些余量。grid.left则把“name 占据的横向空间 + 刻度标签的空间”整体预留出来。实测下来,在 1366 到 2560 宽度的屏幕上都能保持完整显示,不用每个断点单独写死。
echarts.resize只会重绘画布,不会自动计算新的 nameGap,所以如果你的图表容器宽度变化范围很大,建议在 resize 回调里重新 setOption 一次,让动态公式重新执行。
5.3 关于刻度标签、单位、轴名称的分工设计
最后说一个设计习惯。很多图表把单位直接写在刻度标签里,比如120万元、80%,其实并不推荐。刻度标签应该尽量保持简洁,只显示数值,让axisLabel.formatter最多加千分位或小数位,单位交给 name 去承担。这样刻度间距均匀,视觉干净,name 的位置调整也更有意义。
举个例子:如果数据范围从 0 到 10000,标签写10000很清爽,加上单位后变成10000元,标签变宽,name 和刻度之间的间距需求也会变化,还可能出现标签互相重叠。把单位从标签里剥离、放到轴 name 上,是“数据可视化第一性原则”的体现——图形本身负责表达趋势,文字负责补充语境,两者各司其职。
在实际项目里,我通常会给 name 保留一个固定位置:x 轴用middle,y 轴用middle+ 正负 90 度旋转,只有在“强调起始意义”或“图表空间极窄”时才用start或end。这个默认策略让我少踩了很多 text 抢空间的坑,也让我在接手别人图表时,能一眼看出 name 位置是否还有优化空间。记住一个原则:调整 name 位置,永远是在“轴线方位 + 间距 + 旋转 + 网格边距”这四者之间找平衡,而不是盲目堆配置。希望这篇文章能让你下次调 name 时,一次到位。