☰
ECharts grid配置详解:解决图表顶格、贴边及多图布局难题
2026/10/2 5:27:31 网站建设 项目流程

做数据可视化大屏和业务报表这几年,我发现很多人对 ECharts 的抱怨都集中在同一个地方:图怎么又顶格了?标题离上边框就剩一口气,Y 轴文字往左冒出半截,想把图表往下压一压给下面的指标卡让个位,结果 setOption 写了十几行也没动静。说实话,这类问题十有八九都出在同一个家伙身上——grid 组件。

grid 是 ECharts 直角坐标系图表的“地基”,所有柱状图、折线图、散点图的绘图区边界,都由它来控制。你看到的图表“贴边”“被裁”“挤在一起”,本质上不是 ECharts 画错了,而是 grid 区域的上下左右留白不对。这篇文章就围绕 grid 组件,把图表位置调整这件事彻底捋清楚,从最常用的单图定位、多图分块,到 containLabel 的隐性规则、rem 适配下位置失效的坑,全部过一遍。适合刚上手 ECharts 的前端新手,也适合做大屏做到头秃、想救一下布局的“老手”。

1. grid 组件到底是什么,它管哪块地

1.1 grid 对应的就是绘图区的“边界”

很多人一打开官方文档,看到 grid 的配置项那一大屏就有点发怵。其实你可以把它想成一张画布上给图表“圈地”的橡皮筋。

一个常见的直角坐标系图表,画布上存在这些元素:标题 title、图例 legend、x 轴和 x 轴的刻度文字、y 轴和 y 轴的刻度文字、数据图形(柱子、线条、散点)。这些元素不可能都叠在一起,总得有块区域专门画数据图形,轨道四周留出空间给坐标轴文字和别的组件。grid 组件就是用来定义这块“数据图形专用区域”的。

所以 grid 只对直角坐标系系列生效,比如 line、bar、scatter、candlestick。饼图 pie 不走 grid,它用的是 center 定位,这个细节我在第 4 部分专门说。

grid 的默认值其实非常保守,它会让绘图区占满整个容器、然后四周留一点点边距。你要是没配 grid,ECharts 也会按默认参数渲染,所以看到图“顶天立地”很正常。

1.2 定位属性怎么用:left / top / right / bottom 与百分比

grid 里最常用的是四个位置属性:

  • left:grid 区域离容器左边界的距离
  • top:grid 区域离容器上边界的距离
  • right:grid 区域离容器右边界的距离
  • bottom:grid 区域离容器下边界的距离
  • width:grid 区域的宽度
  • height:grid 区域的高度

先说取值。这四个值都可以是数字或字符串。数字就是像素值,比如 left: 80 表示离左边 80px。字符串一般写成百分比,比如 left: '10%',这个百分比是相对容器宽度的。top 和 bottom 的百分比相对容器高度。

这里有个容易绕晕的点:同时设置 left 和 right 时,ECharts 会自动算出 grid 的宽度,这时候 width 可以不写。同时设置 top 和 bottom,height 可以不写。但如果你把 left、right、width 三个都写了,ECharts 实际计算时优先用 left + width,right 相当于被忽略。我在项目里踩过这个坑,调了半天以为 right 没生效,最后发现是 width 写死了。

我来写一个最普通、最常用的例子。

option = { grid: { left: 80, top: 60, right: 40, bottom: 50 }, xAxis: {}, yAxis: {}, series: [ { type: 'line', data: [120, 200, 150, 80, 170] } ] };

假设容器宽 800、高 600,那 grid 区域的计算就是:x 从 80 开始,到 800 - 40 = 760 结束,宽度 680;y 从 60 开始,到 600 - 50 = 550 结束,高度 490。数据图形就画在这块 680 × 490 的区域内。

2. 单图位置调整:从默认“顶满”到自由留白

2.1 一个最常用的“留白”配置

实际开发里,大多数需求并不是要做出多么复杂的多图联动,而是想让一张图好好待在页面里,四周别碰边。这时候我推荐直接用一组相对保守的值,再配合 containLabel 一起用。

先看这段配置:

grid: { top: 70, left: 16, right: 24, bottom: 40, containLabel: true }

为什么 top 要刻意给到 70?因为如果你的容器上方有标题,或者大屏页面上方有一条很占高度的导航栏,那么 grid 区域离顶部太近,数据图形就会和标题贴脸。给到 70px 算是给标题和留白都留了余地。

left 给 16 在 containLabel: true 的情况下通常够用,因为 containLabel 会把 y 轴的刻度文字算进 grid 区域内。right 给 24 是为了让最后一个柱子或者折线末端不贴右边框。bottom 给 40 是因为 x 轴下方除了刻度文字,有时候还要塞 legend、dataZoom,甚至是自己用 HTML 拼的单位说明。

有的同学会问:既然 containLabel 已经把刻度文字算进去了,left 为什么还要给 16?因为 containLabel 只是包含刻度文字,不代表左边一点呼吸感都没有,而且 offscreen 容器或特殊字体渲染时,过小的 left 仍可能造成文字贴边。稳妥起见我习惯至少留 16px。

2.2 containLabel 与刻度文字溢出的账

containLabel 是 grid 组件里最具迷惑性的属性,没有之一。

默认情况下,containLabel 是 false。这时候 grid 区域到底是怎么画坐标轴文字的?我举个例子:你要画一个柱状图,Y 轴刻度文字是“1,500”“2,000”这种很宽的数字。如果 containLabel 为 false,grid 的 left 只控制“柱子区域的左边”在哪里,Y 轴文字是画在 grid 区域左侧之外的。

换句话说,left: 80 时,柱子从 x=80 开始往右排,而 Y 轴文字在这个 80px 宽的左侧区域里渲染。一旦文字宽度超过 left 指定的 80px,文字就会溢出画布左边界,出现“刻度被切掉一半”的效果。

把 containLabel 设为 true 之后,ECharts 会做一次额外的测量:它先算出 grid 区域,再把坐标轴刻度文字的实际尺寸测量出来,然后自动把 grid 区域往右“顶”一点,确保文字完整显示在画布内。

听起来很美好,但注意:containLabel: true 不等于说 left 可以随便填 0。如果 Y 轴文字特别宽,加上 left:0,文字被包含进去了,但数据图形区域会被压得很窄。所以我在调 containLabel 的时候,会先用一个大致预留值,再开 containLabel,看最终渲染效果再微调。

有一个调试技巧:把 grid 的 backgroundColor 临时设成一个半透明颜色,比如 'rgba(255,0,0,0.2)',就能一眼看到 grid 区域到底占多大、数据图形画在哪。调好位置后记得删掉这个属性。

2.3 手动估算绘图区范围

做数据大屏时,经常会遇到“图表在 1920×1080 下刚刚好,换到 1366×768 就崩了”的情况。这时有个手工估算绘图区的思路很实用。

比如容器宽 1920,我要让图表区域大致落在 x=100 到 x=1820 之间。那么 grid.left 设为 100,grid.right 设为 1920 - 1820 = 100。如果容器宽度变了,这两个像素值是按绝对像素来的,不会自动缩放,所以大屏适配时我更推荐用百分比。

grid: { left: '8%', right: '8%', top: '12%', bottom: '8%' }

百分比的好处在于它天然是响应式的,容器怎么变,grid 边界都会按比例跟着变。但它的缺点是,当容器很扁时,top 和 bottom 的百分比会显得过大或过小,因为百分比是相对高度的。实际项目中我经常混用:左右用像素,上下用百分比。比如:

grid: { left: 80, right: 40, top: '10%', bottom: '6%' }

这样左右保持稳定的留白,上下随高度自适应。这也是我在大屏项目中比较推荐的一种混搭策略。

3. 一屏多图:用 grid 数组管理多块“地皮”

3.1 上下双图布局写法

一个容器里塞两张图,最简单的办法是拆成两个 div、分别初始化两个 ECharts 实例。但有些场景必须在一个实例里画多组图,比如两个 x 轴共用、两张图联动 tooltip。这时候 grid 就必须写成数组。

举一个很常见的上下双折线图布局:

option = { grid: [ { left: 70, right: 30, top: 40, height: '35%' }, { left: 70, right: 30, top: '58%', height: '30%' } ], xAxis: [ { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], gridIndex: 0 }, { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], gridIndex: 1 } ], yAxis: [ { type: 'value', gridIndex: 0 }, { type: 'value', gridIndex: 1 } ], series: [ { type: 'line', data: [120, 200, 150, 80, 170], xAxisIndex: 0, yAxisIndex: 0 }, { type: 'line', data: [30, 45, 28, 60, 42], xAxisIndex: 1, yAxisIndex: 1 } ] };

这里 grid 数组里有两块地皮。第一块 top: 40,height: '35%',意思是从顶部往下 40px 开始,高度占容器高度的 35%。第二块 top: '58%',意思是从容器高度 58% 的位置开始往下排,height: '30%'。

有人会问,为什么第二块不直接 top: '40%' 再 height: '35%'?因为如果第一块下方直接紧贴第二块,x 轴刻度文字和 y 轴刻度会挤在一起,视觉上很难受。我把第二块的 top 放在 58% 左右,给中间留出一段空白,相当于给第一块的 x 轴标签和第二块的标题都腾了地方。

3.2 xAxis / yAxis 与 grid 的索引绑定

多 grid 布局里最容易犯错的地方,不是 grid 本身,而是坐标轴和 series 的索引没对上。

xAxis 数组里的第一项默认对应 grid[0],xAxis[1] 对应 grid[1],yAxis 同理。但一旦 grid 之间上下错位了,或者 series 里忘了写 xAxisIndex,图就会画到意想不到的区域去。

我在自己的项目里有个习惯:只要 grid 超过一个,xAxis、yAxis、series 里的索引全部显式写明,绝不靠默认绑定。上面代码里的 gridIndex、xAxisIndex、yAxisIndex,一个都不省。

这么做还有一个好处:当我要调整某张图的位置时,只需要改对应 grid 的 top / left / height,不需要翻 series。比如想让下面的图高一点,就改 grid[1].height 和 grid[1].top,下面的图所有内容会跟着整体移动。

3.3 双图联动位置布局的注意点

很多时候双图不只是上下排布,还要求左右两列,或者一大一小嵌套排布。grid 数组对每个元素都是独立的“地皮”,可以自由组合位置。

比如左侧一个 60% 宽的主图,右侧上下堆两个 30% 左右的辅助图,grid 可以这样配:

grid: [ { left: 60, right: '38%', top: 40, bottom: 50 }, { left: '66%', right: 30, top: 40, height: '35%' }, { left: '66%', right: 30, bottom: 50, height: '25%' } ]

这种布局花点时间就能调好,但要注意标题和图例的占位。如果每个子图都有自己的标题,不能直接用 title 组件——因为 title 是全局的,不能绑定到某个 grid 上,除非用 title 数组并分别指定 top、left。实际做项目时,我更喜欢把多张图拆成多个容器分别初始化,只有在需要共享 tooltip 或者轴联动时才会用单实例多 grid。

4. 那些看起来叫“位置”但不是 grid 管的事

4.1 饼图没有 grid,你调位置用的是 center 和 radius

这个问题我在社区看到过太多次了:“我给饼图配了 grid,为什么图纹丝不动?”答案很简单,饼图不走直角坐标系,grid 是倒腾 x 轴和 y 轴的,饼图上根本没这俩轴。

饼图自己的定位方式是 center 和 radius。

option = { series: [ { type: 'pie', center: ['50%', '50%'], radius: ['30%', '60%'] } ] };

center 接收一个数组,第一项是圆心水平位置,第二项是圆心垂直位置,可以写百分比或像素。radius 如果是数组,第一项是内圈半径、第二项是外圈半径,这样就形成了环形饼图。

大屏布局时我常把饼图 center 设置成 ['50%', '55%'],因为顶部要留出标题和 legend 的空间,圆心视觉中心需要比容器几何中心稍微往下移一点,否则饼图和标题会挤。

另外,饼图的 labelLine 如果觉得和图形挨太近,可以单独调 labelLine 的 length 和 length2,这是控制引导线长度用的,不是 grid 能管的范畴。

4.2 地图的位置由 geo / map 的 center 和 zoom 决定

热词里有 echarts 中国地图,这个也得单独拎出来说。地图组件没有 grid,它靠 center 和 zoom 控制位置和缩放。

geo: { map: 'china', center: [104.0, 37.5], zoom: 1.2 }

center 里填的是经纬度,zoom 是缩放比例。地图展示时如果发现某个区域跑到画布外面,不要想着用 grid 或者 left/top 去推,那些都不管用。正确姿势是调 center 把视野中心移到目标区域附近,再调 zoom 缩放到合适级别。

我实际做中国地图时,默认 center 会偏右或者偏下,一般会手动调到 [104, 37] 左右,再根据画布长宽比微调 zoom。这个值没有一个固定的标准答案,因为不同比例容器下地图的裁切效果差异很大,只能边看边调。

4.3 markPoint 的定位“坐标”是什么

markPoint 也经常被人当成“位置”问题来调,尤其是地图上的标记点。其实 markPoint 是 series 上的配置,坐标语义跟随坐标系:

  • 直角坐标系图表里,markPoint 的 coord 是 [x轴值, y轴值],例如 line 图里 coord: ['Mon', 120] 会标在“周一”那个点上方。
  • 地图系列里,coord 是经纬度,比如 coord: [116.4, 39.9] 就会标在北京附近。

如果你看见 markPoint 位置不对,先检查 coord 数组的语义是不是和当前坐标系匹配。常见错误是在地图上用像素坐标、在折线图上塞经纬度,那肯定是不对的。

5. 位置调整中的高频坑位与排查记录

5.1 containLabel 忘开导致 Y 轴文字被吃

这是新手上路最容易踩的坑,也是我一开始写代码时忽略到怀疑人生的问题。

症状:柱状图左边刻度文字“1,200”显示不全,最前面两位数字被切掉;或者折线图 y 轴单位文字离左边缘只剩半个字符。

原因:grid 默认不把坐标轴刻度文字算进布局。如果你直接写 left: 20,而 Y 轴文字实际需要 60px,那多出来的 40px 就会被画到画布外。

处理:要么把 left 调大,让出足够空间;要么把 containLabel 设为 true,让 ECharts 自动算。两种方式我都试过,结论是 containLabel: true 更省心,但要注意它会让真正绘图区变窄,数据图形整体右移。如果你需要非常精确地控制数据图形起始位置,那就关掉 containLabel、手动把 left 设置成足够大的固定值。

5.2 rem 适配下 ECharts 位置纹丝不动的真相

热搜词里有一条是“pxtorem 对 echarts 没起到效果 vue3”,这个问题我太熟了。

postcss-pxtorem 这类工具只会去转换 CSS 文件里的 px 单位,而 ECharts 的配置项是 JS 对象里的数字,是不经过 postcss 处理的。所以你在 CSS 里写 font-size: 16px,会转成 rem;但在 ECharts 配置里写 grid.left: 16,那 16 就是实打实的 16px,永远不跟着 rem 走。

如果页面整体用了 rem 适配,屏幕一变宽,ECharts 图表区域就会显得“跟不上节奏”。解决思路有三种:

  1. 布局时优先用百分比字符串,比如 grid.left: '10%',这样 ECharts 内部按容器尺寸计算,天然响应式。
  2. 根据 rem 基准换算成像素后再设置到 option 里,然后监听窗口变化重新 setOption。
  3. 计算当前 rem 对应的像素值,作为 grid 左右留白的基数。

我个人最推荐第一种,因为代码最干净,也不需要引入额外的监听逻辑。大屏项目里几乎所有 grid 值我都用百分比,只有少数需要严格对齐的场景才用 px。

5.3 tooltip 溢出与换行

tooltip 虽然不直接归属 grid,但它和“图表位置”强相关,尤其是大屏边缘区域的图表。

默认 tooltip 跟随鼠标位置,但如果图表太靠右,tooltip 提示框可能超出画布右边界,出现一半看不见的情况。处理办法是在 tooltip 里指定 position:

tooltip: { position: function (point, params, dom, rect, size) { // point 是鼠标位置,size 是容器尺寸,dom 是提示框节点 if (point[0] > size.viewSize[0] - 200) { return [point[0] - 220, point[1] + 20]; } return [point[0] + 20, point[1] + 20]; } }

这段代码的意思是:如果鼠标太靠近右侧,提示框就出现在鼠标左边,否则出现在右边。tooltip 内容需要换行时,直接在 formatter 回调里拼<br/>就行,或者给 extraCssText 设置 white-space: pre-wrap,然后 formatter 里用 \n 换行。

5.4 我踩过的多 grid 串轴问题

多 grid 布局中,坐标轴经常出现“串台”。症状是上面图表的折线显示到了下面那块区域,或者两个图表的 y 轴刻度混在一起。

这个问题的根源基本是坐标轴索引没配对。我排查时会按这个顺序检查:

  1. xAxis 数组里的每一项有没有写 gridIndex,写对了没有。
  2. yAxis 数组里的每一项有没有写 gridIndex。
  3. series 里有没有写 xAxisIndex、yAxisIndex。
  4. 如果用的是 dataset 模式,还要检查 dataset 是否与对应 series 绑定。

这里有个小技巧:打开浏览器控制台,用chart.getModel().getComponent('xAxis')查看每个 xAxis 绑定的 grid,能很直观地看出问题出在哪。

还有一个细节,ECharts 里的 grid 和 CSS 里的 display: grid 是完全两码事。我在团队里经常遇到新人把这两个概念搞混,导致一边写 CSS 布局一边疑惑“为什么 ECharts 的 grid 不生效”。简单说,CSS Grid 是页面层面的排版工具,ECharts grid 是图表内部绘图区的定位配置,两者各自为政,不要混在一起调。

最后再分享一个小经验:调 grid 位置不要靠猜,尽量打开浏览器开发者工具,先用第 2 部分提到的 backgroundColor 调试法把 grid 区域可视化,再逐步调整四个边的值。大屏适配时优先用百分比,复杂的多图布局优先用 grid 数组并显式写明所有索引。图表位置这件事本身不复杂,但解决的过程中积累出来的这些细节,才是真正能帮你省时间的东西。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询