ECharts柱状图从入门到实战:堆叠、双轴、大屏优化全解析
发布时间:2026/9/29 1:46:10来源:尧图网络
我在公司接到的第一个数据可视化需求就是画一张柱状图把过去半年的订单量按月份展示出来。当时觉得简单半小时后就交了第一版结果业务方看了一眼就退了回来——柱子挤成一团月份标签全叠在一起悬浮框里还带着英文默认单位。也就是从那次返工开始我才认真把ECharts柱状图从头到尾研究了一遍。这篇文章就是基于那段时间的踩坑和后续十几个项目的经验整理的。ECharts 官方示例里柱状图看起来很简单几行配置就能出图但真正拿到业务里你会发现一堆细节堆叠顺序怎么控制、双轴怎么对齐、柱子上能不能放图片、大屏上 tooltip 怎么换行、动态数据更新要注意什么。这篇文章会把柱状图从基础绘制到各种实际场景中的玩法都过一遍适合刚接触 ECharts 的初学者也适合已经会用基础配置但想在项目里做得更细的人参考。1. 为什么柱状图值得单独写一篇教程1.1 柱状图在业务场景中的地位柱状图大概是所有可视化图表中使用频率最高的一种。电商后台看销量、运营后台看转化、监控大屏看流量凡是“某个时间点对应的数值是多少”或者“几个分类直接比大小”的场景第一反应基本都是柱状图。它比折线图更容易看出数值差距比饼图更适合展示多分类和趋势变化所以在实际项目中几乎不可能绕开。也正因为太常见很多人都默认它简单真到项目里才发现不是那么回事。尤其是数据指标变多之后柱状图很快就不只是“画几根柱子”那么简单了。你可能要同时展示两个量级完全不同的指标可能要在柱子顶部显示汇总信息可能还要让柱子和折线叠在同一个坐标系里。这些组合需求在官方示例里各自有一张图但放同一个项目里时配置会越叠越复杂。1.2 官方示例和真实业务的差距官方示例里的柱状图干干净净几个柱子代表一组数据看个大概。但真实业务里很少有这么简单的情况要么是两个指标放一起但量级差了几十倍要么是希望把上个月和这个月的数据做成堆叠对比要么是需要显示百分比趋势同时还要看原始数值。这些需求在官方示例里各有一张图但放同一个项目里时配置会越叠越复杂Y 轴怎么分配、图例怎么布局、悬浮框怎么展示都要重新设计。就拿我之前做的订单数据屏来说业务方既要看各区域销售额又要看订单量还要对比目标完成率。最开始我只放了一个柱状图销售额 8000 的时候订单量才 20 多订单量的柱子完全被压制在坐标轴底部肉眼根本看不出区域差异。后来换成了双轴柱状图加目标进度条才把信息完整呈现出来。这也是为什么我不建议“背配置”而是建议先理解柱状图的数据映射逻辑。1.3 从这篇文章能得到什么这篇不是一份让你背配置的文档我会照着实际项目的推进顺序来写先跑通一个最基础的图再一步步加需求维度最后讲优化方案和踩坑记录。你可以按顺序读也可以直接跳到对应的需求段落把配置抄走。文中代码基于 ECharts 5.x早期版本的大多数配置也兼容注意个别 API 的差异即可。2. 从零跑通一个最简柱状图option结构是理解一切的基础2.1 先写一个能跑起来的最小例子ECharts 的使用套路其实非常固定一个 DOM 容器、一个初始化方法、一个 option 配置对象、一次 setOption。所有图表类型都逃不出这个流程柱状图只是 option 中 series 的 type 设为 bar。!DOCTYPE html html head meta charsetUTF-8 script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script /head body div idmain stylewidth: 600px; height: 400px;/div script const chartDom document.getElementById(main); const myChart echarts.init(chartDom); const option { xAxis: { type: category, data: [周一, 周二, 周三, 周四, 周五, 周六, 周日] }, yAxis: { type: value }, series: [ { name: 订单量, type: bar, data: [120, 200, 150, 80, 170, 110, 230], itemStyle: { color: #5470c6 } } ] }; myChart.setOption(option); /script /body /html这段代码跑起来页面里就会出现七根柱子。很多教程到这里就完了但我想多说几句背后的结构因为后面所有复杂配置都是在这个结构上叠加的。2.2 直角坐标系中的柱状图是怎么回事柱状图的本质是直角坐标系里把数值转换成高度。xAxis 配置的是类目轴也就是柱子在水平方向上的位置yAxis 配置的是数值轴决定柱子有多高。series 里的 data 数组负责把数值“喂”给 y 轴每个值和 xAxis 的 data 按索引一一对应。这里有个容易忽略的点x 轴和 series 的 data 是按索引对齐的不是按值匹配。所以 xAxis.data 是 [周一, 周二, 周三]series.data 就必须是三项。如果顺序乱了柱状图上显示的类别和数值就会错位而且 ECharts 不会报错这种错误在项目里很难发现。我建议在做动态数据时前端就先把数组对齐好再传进去不要依赖后端返回的字段顺序。2.3 柱子宽度、间距和上下边界是怎么决定的柱子的宽窄不是浏览器随机决定的背后有一套分配规则。ECharts 会先计算类目轴的带宽bandWidth再按barCategoryGap决定不同类目之间的空隙比例按barGap决定同一类目下不同系列之间的空隙比例。默认barCategoryGap是 20%意味着类目间距占整个带宽的 20%。实际项目里默认值经常不够用我会直接指定series: [{ type: bar, barWidth: 20, // 直接指定柱子宽度单位像素 barMaxWidth: 40, // 柱子宽度上限防止数据少时柱子胖得离谱 data: [/* ... */] }]barWidth和barMaxWidth的选择取决于容器宽度和分类数量。我的经验是分类少于 6 个时柱子宽度设在 20-30 像素比较协调分类超过 12 个时不要固定 barWidth改用 barMaxWidth 限制上限让 ECharts 自己压缩否则柱子之间会挤到几乎贴在一起。2.4 轴上的文字太挤怎么办一个最常见的返工理由就是 x 轴标签重叠。尤其是分类多、文字长的时候默认配置几乎必挤。三个常用处理思路加间隔xAxis.axisLabel.interval 0是强制全部显示如果重叠就调大数值。旋转xAxis.axisLabel.rotate 30让长标签斜着展示。隐藏部分axisLabel.hideOverlap: true自动隐藏重叠的标签。这三个方案没有绝对优劣。我一般先试hideOverlap再考虑rotate因为用户读图时第一眼想看的是整体柱子趋势而不是每个分类都标出来。只有极少数场景需要每个分类都显示那时候才用interval: 0配合旋转。3. 柱状图的三种高频变形堆叠、双轴和横向布局3.1 堆叠柱状图多个系列叠成一根柱子需求方说“我想看看两种商品的销量合计还想看各自占了多少”这时候堆叠柱状图是最直接的方案。做法是在多个系列的配置里给同一个 stack 值这些系列就会在同一个类目下像叠积木一样叠起来。series: [ { name: 手机, type: bar, stack: total, data: [320, 302, 301, 334, 390, 330, 320] }, { name: 电脑, type: bar, stack: total, data: [120, 132, 101, 134, 90, 230, 210] } ]这里有个隐藏逻辑堆叠后后续系列的柱子不是从零开始画而是从上一个系列的顶部开始画。所以 series 数组里的顺序就决定了堆叠的上下顺序。我建议把数值较大的系列放下面视觉上更稳当数值极小的系列如果放在底层它的颜色区域可能会被上面系列遮住看不清这一点在配置时需要特别留意。堆叠的另一个用途是做“目标达成拆解”。比如把销售额拆成新客和老客两部分堆叠起来既能看到总数又能看到结构变化。如果只想看占比可以给 yAxis 配置max: 100然后数据改成百分比这样柱子高度恒定但分区比例变化明显。3.2 双轴柱状图量级差异大时的常用处理一个业务场景既要看销售额几千块又要看订单量几十个。如果共用一个 y 轴销售额会把订单量压成一条贴地的线。此时可以给右侧再加一条 y 轴。yAxis: [ { type: value, name: 销售额, position: left }, { type: value, name: 订单量, position: right } ], series: [ { name: 销售额, type: bar, yAxisIndex: 0, data: [3200, 4300, 5200, 4100, 6300] }, { name: 订单量, type: bar, yAxisIndex: 1, data: [15, 22, 18, 30, 27] } ]双轴图的核心是yAxisIndex。series 里的yAxisIndex为 0 表示用第一条 y 轴左侧为 1 表示用第二条 y 轴右侧。不写就默认用 0。看起来简单但在多系列时特别容易漏配导致所有柱子都在左侧轴上对齐量级图形失真。双轴图有个常见争议两个 y 轴的刻度范围是独立计算的所以两组数据之间的视觉关系可能是“假”的。比如左侧销售额 0-10000右侧订单量 0-50一眼看过去两者的柱子高度对比并不代表真实比例。在给业务方讲解时要提前说明这一点否则容易被误读。如果单纯为了对比两组数据的趋势其实也可以用双折线图或普通单轴归一化处理。3.3 横向柱状图分类名特别长时的救星当分类名称很长比如“华东大区-杭州萧山仓”、“华南大区-深圳宝安仓”x 轴无论如何旋转都放不下时直接把图反过来用横向柱状图是最稳妥的。做法就是把 xAxis 和 yAxis 的类型换一下类目轴放到 yAxis数值轴放到 xAxis。xAxis: { type: value }, yAxis: { type: category, data: [华东大区-杭州萧山仓, 华南大区-深圳宝安仓, 华北大区-北京大兴仓], inverse: true // 让第一个分类显示在最上面 }inverse: true是我个人比较推荐加上的否则默认第一个分类出现在 y 轴底部读起来别扭。这种横向布局在移动端也友好屏幕宽度有限时横向列表比竖向柱状图高效得多。横向柱状图还可以配合label: { position: right }让数值显示在柱子右侧而不是柱子上方长分类名时更不拥挤。4. 柱子的“卖相”工程渐变、圆角、图片柱和标签布局4.1 渐变是提升图表质感的最直接手段业务大屏上纯色柱子总显得单薄渐变色是提升质感最廉价的方案。ECharts 里的渐变不是写 CSS 的 linear-gradient 字符串而是用echarts.graphic.LinearGradient对象。itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #83bff6 }, { offset: 1, color: #2f6fed } ]) }参数里的四个数字是渐变方向(0, 0)表示起始点在左上角(0, 1)表示结束点在右下角这样是垂直渐变。如果想让柱子从上到下颜色由浅变深就用(0, 0, 0, 1)想让柱子从左到右渐变用(1, 0, 0, 0)。渐变还有个额外好处同一色系渐变比纯色更容易分辨不同柱子尤其是柱子数量多的时候。但要注意渐变对象的 offset 从 0 到 1 必须连续中间留白会出现颜色断层视觉上很难看。4.2 圆角柱子的注意点圆角柱子上手很快itemStyle: { borderRadius: [6, 6, 0, 0] }四个值分别对应左上、右上、右下、左下。顶部两个角圆润底部保持直角看起来像从地面长出来的柱子这是目前业务项目里最常见的样式。但堆叠柱状图里圆角要小心。如果每段都设置borderRadius: [6, 6, 0, 0]中间层的柱子上下都直角顶部层的柱子有圆角但堆叠的边界处会有割裂感。一般建议只在最底层加底部圆角、最顶层加顶部圆角中间层保持直角。如果实在想统一加圆角可以把圆角设成小值比如[3, 3, 3, 3]视觉上不会太突兀。4.3 柱子的颜色怎么规范不要依赖默认色板项目里我强烈建议给每个系列固定颜色不要依赖默认色板。默认色板在系列超过一定数量后会重复或不够用而且换主题时颜色会变业务方会质疑“为什么上周还是红色这周变绿了”。如果系列多可以用一个数组循环取色const colorList [#5470c6, #91cc75, #fac858, #ee6666]; const data [100, 200, 150, 120]; const seriesData data.map((value, index) ({ value, itemStyle: { color: colorList[index % colorList.length] } }));这里循环取色的好处是即使数据长度超过颜色数量也不会报错顶多颜色循环不会出现 undefined。如果项目中有设计规范建议把品牌色做成常量文件在多个图表里复用保证整个页面的视觉统一性。4.4 柱子上能不能放自定义图片可以网上经常有人问“ECharts 柱状图的柱子能不能用自定义图片显示”。答案是可以的不用改什么特殊配置还是走itemStyle.color但传的是一个带 image 属性的对象。const img new Image(); img.src /images/cola.png; series: [{ type: bar, data: [120, 200, 150], itemStyle: { color: { image: img, repeat: repeat } } }]repeat: repeat表示图片在柱子里平铺柱子多高就铺多少层。这种效果适合做带纹理的柱子比如饮料销量图让柱子填充饮料包装图。这里有个先决条件图片要先加载完成再 setOption否则可能出现空白柱子。我通常在img.onload回调里再调用 setOption或者在页面初始化时就预加载好图片资源。如果不想用纹理填充还有一种思路是柱子本身用透明或弱色然后在柱子的顶部加一个图片标记类似 markPoint 的效果这样柱子和图片是分开的加载失败时还能退回到纯色柱子。4.5 柱子上的数值标签在柱子上显示具体数值用label配置label: { show: true, position: top, color: #333, fontSize: 12 }当柱子很高时标签放在top可能会超出容器这时可以设置overflow: break配合width或者在 label 的 formatter 里对数值做单位转换比如超过 10000 显示为“1.2万”。我在电商项目里经常用这个技巧否则数值标签会占掉大半张图柱子反而成了背景。标签的 formatter 可以做很多事情不只是加单位还可以加前后缀、换行、根据数值大小变颜色。比如label: { show: true, position: top, formatter: function (params) { return params.value 1000 ? (params.value / 1000).toFixed(1) k : params.value; } }这样柱子上就不会显示一长串数字既美观又容易读。5. 柱状图叠加折线图我最常用的一套组合图配置5.1 这类图适合什么场景柱状图叠加折线图的场景一般是柱状图展示绝对值折线图展示比率或另一个量级的指标。典型的就是“销售额柱状图 增长率折线图”大屏上报表里出现频率非常高。这个需求用到的基础是双轴再混合不同 series 类型。柱状图和折线图在同一个坐标系里既有对比又有趋势是信息密度比较高的一种组合。5.2 完整配置可以直接抄option { tooltip: { trigger: axis, formatter: function (params) { let res ; params.forEach(function (item) { if (item.seriesName 销售额) { res item.marker item.seriesName item.value 万元br/; } else { res item.marker item.seriesName item.value %br/; } }); return res; } }, legend: { data: [销售额, 增长率] }, xAxis: { type: category, data: [1月, 2月, 3月, 4月, 5月, 6月] }, yAxis: [ { type: value, name: 销售额万元, splitLine: { show: true } }, { type: value, name: 增长率%, splitLine: { show: false }, axisLabel: { formatter: {value}% } } ], series: [ { name: 销售额, type: bar, yAxisIndex: 0, data: [120, 200, 150, 80, 170, 240], itemStyle: { borderRadius: [4, 4, 0, 0] } }, { name: 增长率, type: line, yAxisIndex: 1, smooth: true, data: [12, 18, -5, 24, 30, 35] } ] };5.3 组合图里必须注意的对齐问题这类组合图看着简单但有几个细节容易踩坑。一是右侧 y 轴的splitLine: { show: false }这样图上的网格线只有左侧销售额的右侧增长率不再重复画线否则背景会显得特别乱。二是 y 轴范围没对齐时折线会被“压扁”或“拉飞”。ECharts 默认自动计算但两个轴的数值范围往往差距很大。比如销售额在 0-240增长率在 -5 到 35如果不设置min/max折线会显得特别平。我一般会给右侧 y 轴设置min: 0或者根据业务设个对称范围让折线的波动幅度在视觉上更明显。三是 tooltip 换行。搜索结果里经常有人搜 “echarts tooltip 自动换行”本意是悬浮框里多个系列的内容不要挤在一行。用 formatter 手拼 HTML 是最直接的方案每行用一个br/结尾就像上面代码里那样。如果项目里 tooltip 复杂建议单独抽一个格式化函数来维护别全堆在 option 里。5.4 折线图上的数值可以不显示但趋势要有组合图里折线图一般不需要显示每个点的数值重点看趋势。如果确实要显示用label: { show: true, position: top, formatter: {c}% }折线图的数据点多了以后可以把symbolSize调小或者设成 0 只留线视觉上更干净。不过 symbolSize 设成 0 之后tooltip 触发时用户不容易点中数据点建议至少保留 4-6 像素的 symbol增强交互手感。6. 大屏项目里柱状图的细节打磨和深坑记录6.1 容器初始化为 0 导致图表不出现做可视化大屏时最经典的坑是图表所在的 div 在初始化时是隐藏的或者宽度为 0ECharts 初始化出来的图表就宽 0 高 0等容器显示出来图表也回不来。排查时控制台还不报错只显示一张空白图。这种问题经常出现在 Tab 页、折叠面板、弹窗这类动态展示的容器里。我的常规做法是统一封装一个 initChart 方法初始化后延时几百毫秒主动调一次resize()function initChart(domId) { const dom document.getElementById(domId); const chart echarts.init(dom); setTimeout(() chart.resize(), 200); return chart; }如果还是不行检查父容器是不是有display: none的样式或者有没有被 transform 缩放到 0。这类问题光靠 resize 也解决不了必须保证初始化时容器可见。6.2 窗口尺寸变化时图表要及时 resize浏览器窗口变了图表不会自动跟着变。需要监听 resize 事件window.addEventListener(resize, function () { myChart.resize(); });这个监听能解决大部分问题但有两个例外一是页面隐藏再显示时容器尺寸变了但没触发 resize 事件需要在前端路由切换或 Tab 切换时手动调用 resize二是大屏缩放方案中整个页面用 transform 等比缩放时图表内部需要重新计算光靠 resize 不够建议结合具体缩放方案统一处理。如果是 Vue 或 React 项目还要注意在组件卸载时移除 resize 监听避免内存泄漏和重复触发。6.3 数据量大的时候柱子怎么优化如果一年 365 天每天一组数据柱子全画出来不仅图面拥挤渲染性能也会下降。几个常用手段barMaxWidth: 10限制柱子最大宽度避免太宽像墩子。dataZoom加缩放条只展示部分数据。对数据进行前端聚合比如按周或按月汇总。关闭不必要的动画animation: false大数据量时动画反而拖慢首屏渲染。我遇到过一个场景是每分钟一个数据点一天 1440 个柱子。这时候第一屏根本不需要全部展示我用dataZoom默认显示最近 50 个点用户可以通过缩放条查看历史数据这样性能不会崩交互也比一次性渲染 1440 根柱子好得多。6.4 常见报错排查记录我在带项目时发现新手报错的几种情况整理成一张表报错/现象常见原因处理方式Cant get DOM width or heightinit 时容器不存在或大小为 0确认 DOM 已渲染设置容器宽高图表空白但不报错data 为空数组或全 null打印 data 检查注意 null 值展示柱子和轴标签错位series.data 和 xAxis.data 长度不一致统一数据源长度前端处理好对齐双轴图表柱子全贴一边series 的 yAxisIndex 未设置或设错按系列明确指定 yAxisIndexsetOption 后图例不更新legend.data 没同步legend 的 data 要随 series 更新6.5 动态数据更新setOption 的正确姿势实时报表经常要每几秒刷新一次数据。很多人会直接chart.clear()再重新 init其实没必要。正确的做法是复用同一个实例直接调 setOptionECharts 内部会做 diff 并增量更新setInterval(() { myChart.setOption({ series: [ { data: getNewData() } ] }); }, 5000);注意这里没写 type只写了 data。ECharts 会根据已有的 series 配置做更新这是官方推荐的“增量更新”写法。如果每次都把完整 option 塞进去视觉上容易闪动交互也会卡。动态更新时还有个容易忽略的点如果数据长度会变化xAxis 的 data 也要一起更新。只更新 series.data 而 xAxis.data 不变就会造成前后数据错位。我在实时监控项目里的做法是每次更新都同时 setOption 里带 xAxis.data 和 series[0].data保持一致。我自己在那次返工之后总结了一句话柱状图的复杂度不在画几根柱子而在真实业务里围绕这些柱子产生的需求细节。配置项记不住没关系能查文档就行但要知道一个问题大概从哪个配置入手知道怎么排查数据错位、怎么处理容器尺寸、怎么控制双轴这些经验才是项目里真正值钱的部分。希望这篇教程能帮你少走一点弯路。
网站建设高端定制企业官网