ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ECharts grid组件从入门到进阶:彻底掌握图表位置与留白布局

ECharts grid组件从入门到进阶:彻底掌握图表位置与留白布局 做数据可视化大屏这几年我几乎每周都会在群里看到同样的问题折线图右侧最后一个数据点被切了一半、柱状图的 Y 轴文字“砍头”了、图表紧贴着容器边缘一点呼吸空间都没有。大多数人第一反应是去调容器 div 的样式或者在 axisLabel 的 margin 上疯狂加数值很少有人第一时间想到真正管这件事的组件——grid。grid 组件是 ECharts 直角坐标系绘图区的定位核心它决定折线图、柱状图、散点图这一类图表的绘图网格在整个画布里的位置和尺寸。标题、图例、tooltip 这些组件都独立于 grid 之外所以经常出现“我调了图例但图表还是挤在一起”的情况。这篇内容我会从组件本身的作用讲起把 left/right/top/bottom、width/height、containLabel 这几个关键配置一次性讲透再多讲几个我在大屏项目里被坑过的实际场景适合刚接触 ECharts 两个月、正在被图表布局折磨的前端同学。1. 先搞清楚 grid 管的到底是哪一块“地”很多新手对 grid 的误解是从画布和绘图区的概念混淆开始的。ECharts 初始化之后整个 canvas 画布是容器 div 的大小但画布内部还有一块子区域专门给坐标系和图形用这块子区域的边界才是 grid 控制的区域。1.1 绘图区与画布区别把整个 Canvas 当成图表区域你可以把 grid 理解成一张宣纸上用墨线框出的临摹格线条、数据点只能落在格子里格子外面的天地不归 grid 管。坐标轴、刻度线、网格线都贴着这个矩形框生成图形系列也在这个框内绘制。但刻度的文字标签比较特殊它是在轴旁边延伸出来的默认并不算在 grid 区域内。打个更生活化的比方你给一幅书法作品装裱grid 就是内芯的边框标题和图例是挂在边框外的题跋而刻度文字是那些会“探出头”的笔画。你调边框位置改不了题跋的位置也控制不了笔画探出多少除非你单独设置 containLabel 去约束探出的部分。这个区分在实际项目里非常关键。如果你发现整个图表包括标题、图例、坐标轴文字都偏左了想通过 grid.left 把所有内容一起右移结果发现标题纹丝不动不要怀疑配置写错了——因为 grid 只管绘图区title 和 legend 有自己独立的定位体系。1.2 受 grid 管制的图表类型与非管制类型ECharts 的图表家族里直角坐标系依赖的图表都受 grid 影响包括 line折线图、bar柱状图、scatter散点图、candlestickK线图、effectScatter涟漪散点等等。它们的共同点是必须有 xAxis 和 yAxis而 grid 就是这两个轴所在的容器。但饼图pie用的是 center 和 radius 来定位雷达图radar用 indicator 和 radar 组件地图map用 geo 或 map 实例树图、矩形树图、桑基图等等都有自己独立的布局算法这些完全不看 grid。最容易踩坑的是混合图表场景一张图里同时有 bar 和 pie你把 grid.left 调大想给右侧让位结果发现饼图一点没动。原因很简单饼图是绝对定位center 坐标决定圆心它不参与 grid 的布局计算你需要单独把 pie.center 的 x 坐标调大才行。2. 控制图表位置的六个属性按场景选对写法grid 真正决定位置的就是六个属性left、right、top、bottom、width、height。它们可以单独使用也可以组合使用但组合时要注意属性和属性之间的优先级关系。2.1 数值、百分比、auto 三种写法各自适用什么场景left、right、top、bottom 的写法有三种数值number单位是像素例如left: 80表示 grid 区域左边界距离容器左侧 80 像素。适合设计稿固定、不需要随屏幕变化的位置。百分比string例如left: 8%表示距离容器左侧 8% 的宽度。适合自适应布局和不同分辨率大屏。auto让 ECharts 根据轴名、刻度标签、图例等因素自动计算位置。适合快速出图但同一台设备上换个轴文本长度图表位置就可能发生变化二次微调时不建议依赖它。width 和 height 的优先级比较特殊一旦显式设置了 widthright 就会被忽略因为左侧由 left 决定、右侧由 left width 决定此时 width 的优先级高于 right。同理一旦设置 heightbottom 就会被忽略。这个机制用好了可以固定图表区域大小用不好就会出现“我明明设置了 right 为什么图表缩不回去”的困惑。2.2 一个实战改动折线图右侧数据点被切掉假设你初始化了一个折线图默认配置下最右侧的 symbol 明显离容器边缘太近甚至出现半个点被裁切的情况。这种问题通常是 grid 默认的 right 值不够而 symbol 又正好绘制在最后一个类目上导致的。我一般这样处理option { grid: { left: 70, // 左侧给 Y 轴刻度文字留足空间 right: 40, // 右侧多留一点给最后一个 symbol 呼吸空间 top: 30, // 顶部给标题或图例留位 bottom: 50 // 底部给 X 轴旋转后的文字留位 }, xAxis: { type: category, data: [一月, 二月, 三月, 四月, 五月], axisLabel: { rotate: 30 // 旋转文字后底部需要的空间更大 } }, yAxis: { type: value }, series: [ { type: line, data: [120, 200, 150, 80, 170] } ] };当 X 轴文字旋转了 30 度原来默认的 bottom 就不够用了文字会斜着溢出画布底部。此时把 bottom 从默认值加到 50 甚至 60比单纯调 axisLabel.margin 更保险因为你是从布局层面预留了空间而不是硬挤。我在调这类问题时的判断表大概是这样的现象优先调整的属性推荐思路图形被左侧文字挤扁left给 Y 轴刻度文字留 50px 以上最后一个点或柱子贴右边缘right设置为 symbol 直径的 1.5 倍左右X 轴文字旋转后底部溢出不完整bottom旋转 30 度时至少 50px 起步顶部被图例或标题挡住top先量图例高度再决定 top 数值想让绘图区本身固定宽度left width这时 right 会自动失效3. containLabel解决“刻度字被切掉”的隐藏开关很多项目的图表被切成“半张脸”问题不在 left 或者 bottom 没设置而是忽略了一个非常关键的布尔值——containLabel。3.1 containLabel: false 是默认值也是文字溢出的根源默认情况下grid 区域不把坐标轴的刻度标签算进去。也就是说你用left: 20把绘图区放得很靠左Y 轴的刻度文字比如 100、200、300 这些数值实际显示在 grid 外部的左侧如果容器的左边界离 grid 只有 20px这些文字大概率会被 canvas 截断。同理X 轴底部的分类文字如果很长即使设置了bottom: 10文字也可能会溢出到容器外。很多人的第一反应是把 bottom 加到 120让整体下移这当然也能凑效但不够优雅。直接设置containLabel: true是更通用的做法。3.2 containLabel 为 true 时 grid 的扩张逻辑containLabel: true的含义是grid 区域在计算位置时会把坐标轴刻度标签占用的空间也包含进去。当某个方向的空间不够放标签文字时ECharts 会自动扩张 grid 在这条边上的留白直到文字完整显示为止。举个例子你设置了left: 20加containLabel: true而 Y 轴左侧刻度文字实际需要 60px 才能完整显示那么最终渲染时网格的左边界会从距离容器左侧 20px 被退到 60px 左右而不是生硬地把文字截断。这个“退让”过程是自动发生的所以如果你设计稿要求图表必须贴紧左侧某个固定位置反而不能简单依赖 containLabel而是要把 left 手动留够并用containLabel: false确保位置精确。我通常的建议是大部分需要快速上线的后台系统直接containLabel: true保证可读性优先需要在 1920 设计稿上严格执行位置的数字大屏才用containLabel: false手动精调。4. 一图多 grid做数据大屏时的上下分栏布局当页面要展示“销售额趋势 用户增长率”两组数据或者要求两个图表可以共用一个 tooltip、共用 dataZoom 联动滚动时最推荐的做法不是一个页面里初始化多个 ECharts 实例而是一个实例里配置多个 grid。4.1 grid 数组的配置方式与单个 grid 的区别单个折线图或柱状图grid 是对象多个 grid 共存时grid 写成数组同时 xAxis、yAxis、series 也要用数组并且通过 gridIndex / xAxisIndex / yAxisIndex 建立绑定关系。option { grid: [ { left: 60, right: 30, top: 30, height: 35% }, { left: 60, right: 30, top: 55%, height: 35% } ], xAxis: [ { type: category, gridIndex: 0, data: [A商品, B商品, C商品] }, { type: category, gridIndex: 1, data: [Q1, Q2, Q3] } ], yAxis: [ { type: value, gridIndex: 0 }, { type: value, gridIndex: 1 } ], series: [ { type: bar, xAxisIndex: 0, yAxisIndex: 0, data: [120, 200, 150] }, { type: line, xAxisIndex: 1, yAxisIndex: 1, data: [50, 80, 120] } ] };在这个配置里第一个 grid 的高度是容器的 35%第二个 grid 的 top 从 55% 开始高度也是 35%中间自然留出了 20% 的间隙。这个间隙看起来很大实际渲染时可以把 tooltip、联动高亮都稳定地放在空当里不会互相遮挡。4.2 多 grid 排布时的对齐心法多 grid 最容易出现的问题是左右两侧对不齐。比如第一个 grid 的 left 是 60第二个 grid 的 left 是8%容器宽度一变两个绘图区的左边界就不可能落在同一条竖线上视觉上会很乱。我的经验是同一页面的多个 gridleft 和 right 必须用完全一样的值或百分比让它们天然对齐top 和 height 要精确计算最好用百分比因为百分比能跟随容器高度变化。如果两个 grid 之间需要放一些独立的图例或分析文字可以在它们之间保留 8% 到 15% 的间距。别把第二个 grid 的 top 直接设成第一个 grid 的 topheight 加个 2px文字稍微长一点就会贴在一起非常影响观感。5. 大屏适配里那些把位置搞乱的隐形坑这一节是我自己在真实项目里被反复教育的几个问题搜索热度也比较高比如“pxtorem 对 echarts 没起到效果”“tooltip 自动换行”“混合图表位置不联动”等等。很多人以为是 ECharts 的 bug其实多半是定位体系没分开。5.1 pxtorem 对 ECharts 配置无效的根因postcss-pxtorem 这类工具只能处理 CSS 文件里的 px 单位而 ECharts 的 option 是 JavaScript 对象。也就是说你在grid: { left: 100 }里写的是数字 100不是 CSS 属性pxtorem 根本不会扫描到它更不会把它转成 rem。这是一个工具链层面的定位差距。大屏适配时正确做法是自己写一个换算函数根据设计稿宽度和当前窗口宽度计算缩放比例const DESIGN_WIDTH 1920; const scale window.innerWidth / DESIGN_WIDTH; option { grid: { left: 80 * scale, right: 30 * scale, top: 60 * scale, bottom: 50 * scale } };窗口尺寸变化后重新 setOption或者配合chart.resize()触发重新渲染。这一套逻辑比期待 pxtorem 参与 JS 计算要可靠得多。另外要注意不要在 option 里贸然写left: 10rem这种字符串ECharts 的定位配置对 rem 的支持并不是所有版本、所有配置项都有保证直接用换算后的数字像素值最稳妥。5.2 tooltip 被 canvas 切断时该调的其实不是 grid经常有人把 tooltip 显示不全和 grid 位置混为一谈。tooltip 默认出现在鼠标位置附近如果内容太长它可能溢出 canvas 边框而被切掉。这是 tooltip 的定位策略问题不是 grid 的布局问题。解决办法是在 tooltip 里设confine: true让它限制在容器内显示或者用extraCssText控制最大宽度和自动换行。tooltip: { trigger: axis, confine: true, extraCssText: max-width: 240px; white-space: normal; word-break: break-all; }但是有一种情况确实和 grid 有关如果grid.right设置得太小最后一个数据点离容器右边太近tooltip 跟随鼠标移动到那里时即使 confine 生效也会被压得很扁。这时候把 right 调大给 tooltip 留出触发和展示空间效果会明显变好。总之要分清楚是“绘图区位置”的问题还是“浮层定位”的问题。5.3 整体平移图表时grid 不是万能工具如果你想把这整张图包括标题、图例、坐标轴、图形全部向右平移一段距离靠调 grid 是做不到的因为 grid 只能移动绘图区域。我的做法通常有两种一是调整容器 div 在页面布局中的位置比如用 flex 或 margin 处理二是用 ECharts 的 graphic 组件把整组内容包起来平移但这种方式成本较高大部分场景没必要。真正需要精确定位时优先考虑页面布局层面解决而不是死磕图表内部。6. 定位调试的土办法和一套通用模板写 ECharts 配置最怕的是“凭感觉调像素”。实际调试时我有一套很固定的套路能快速判断 grid 到底画在了哪里。6.1 利用 backgroundColor 和 getRect 快速画出边界grid 组件本身支持backgroundColor、borderColor、borderWidth这些样式配置。调试时临时加上这几项把 grid 区域直接显示成一个带边框的色块图表出来后就一目了然grid: { left: 70, right: 40, top: 30, bottom: 50, backgroundColor: rgba(255, 0, 0, 0.08), borderColor: #ff0000, borderWidth: 1 }确认完位置后把这些样式删掉就行。另一个更隐蔽的方法是直接读 grid 的渲染矩形const gridModel chart.getModel().getComponent(grid, 0); const rect gridModel.coordinateSystem.getRect(); console.log(rect); // 输出如 { x: 70, y: 30, width: 900, height: 400 }这样就能拿到 grid 实际渲染出来的像素坐标和宽高配合浏览器元素面板能非常清楚地看出哪儿多了、哪儿少了。6.2 自适应场景下的通用 grid 模板我最近在两个可视化项目里用的都是下面这套基础配置适配性比较可靠grid: { left: 8%, right: 5%, top: 60, bottom: 50, containLabel: true }当容器宽度变化时左右用百分比解决顶部给标题和图例留固定 60px底部给 X 轴文字留固定 50px如果文字旋转超过 30 度再往上加到 60 到 70px。containLabel 开启后即使某个轴的刻度文字意外变长也不会溢出画布。这套模板不是万能的但它能在项目初期把 80% 的位置问题挡在门外。如果在大屏场景下需要更精确的比例可以把 top 和 bottom 也改成相对容器的百分比比如 top: 8%, bottom: 12%并配合 window.resize 事件统一缩放。无论用哪种方案核心原则是不变的先确认绘图区再调组件最后才是改系列图形。少在这个顺序上跳步ECharts 的布局问题基本都能稳稳解决。
返回列表