Echarts教程第一篇写完后,不少朋友在后台问我,为什么第二篇不讲地图或者饼图,偏偏要先讲柱状图。我的答案是:柱状图是Echarts所有图表类型里“性价比”最高的一种——配置项不算复杂,但基本覆盖了坐标轴、系列、图例、tooltip、数据绑定这些核心概念,你把柱状图吃透了,后面学折线图、散点图、饼图基本就是换个series类型的事。而且柱状图在业务里的出场率极高:销售数据的月度对比、不同渠道的转化率、各区域库存量、排行榜……凡是“比大小”的场景,柱状图都是第一选择。这篇教程我会从零开始,把一个柱状图从“能画出来”讲到“能拿得出手”,中间穿插大量我在实际项目中踩过的坑和验证过的方案,适合刚接触Echarts的初学者,也适合已经用过但想系统补一补配置细节的朋友。
1. 柱状图的核心价值与Echarts的体系化认知
1.1 为什么业务可视化永远离不开柱状图
柱状图本质上是“长度编码”的视觉映射,人眼对长度的判断比对面积、角度、颜色都要敏感,所以在展示离散类目下的数值对比时,柱状图是最直观的呈现方式。举一个我常用来跟产品经理沟通的例子:给一份全年12个月的营收数据,用表格看是一堆数字,用饼图看12个扇区角度很难比出大小关系,但用柱状图一摆出来,哪个月高哪个月低一眼就清楚了——这就是长度编码的优势。
在Echarts的组件体系里,柱状图(bar)属于直角坐标系系下的图表,它依赖于grid、xAxis、yAxis这几个基础组件。学习柱状图的过程中,你其实是在同时建立对Echarts“组件化配置”的认知习惯:一个完整的option由若干组件组合而成,每个组件负责一件事,组件之间通过坐标轴、系列名这些约定来产生关联。这个认知一旦建立,后面无论画什么图,都能快速理解配置项的组织逻辑。
1.2 canvas与svg渲染模式怎么选
Echarts从4.0开始同时支持canvas和svg两种渲染模式,柱状图默认使用canvas。这里有一个很多初学者不知道的点:如果柱状图的柱子数量很少(比如只有几个类目),用svg渲染反而能得到更锐利的边缘,因为svg是矢量描述,不依赖像素;但如果柱状图有几百上千根柱子,svg的DOM节点数量会爆炸,canvas的“画布式”渲染能扛住更大的数据量。
实际项目中我的选择标准是这样的:柱状图类目数在50以内、对高清屏显示要求高(比如大屏1080p转4K显示),我用svg;类目数特别多,或者需要频繁动态更新数据,我用canvas。设置方式是在初始化的时候给第二个参数传renderer字段。这一点很容易被忽略,但真正遇到“柱子边缘发虚”“图表卡顿”这些诡异问题的时候,渲染模式的调整往往就是解法。
2. 搭好环境:引入Echarts的三种方式与容器尺寸的坑
2.1 从script标签到npm包,按场景选引入方式
如果你只是想在页面上快速验证一个柱状图的效果,最直接的方式是用CDN的script标签引入。直接在页面里写一个div容器,再引入Echarts的js文件,然后初始化,三步就能看到图表。这种方式适合写demo、做单页小工具,或者是在像“头歌”这类在线实训平台里完成“第1关:Echarts中柱状图的绘制”练习时使用,零配置成本。
但如果你在做正式的前端工程化项目,用npm安装echarts包是更合理的选择。在Vue3或者React项目里,可以按需引入,只把bar图表、直角坐标系组件、tooltip组件这些用到的模块打包进去,这样能显著减小打包体积。我做企业级数据可视化项目时,一般会封装一个统一的图表组件,内部维护Echarts实例的生命周期,避免每个页面都重复写初始化、resize、销毁这三板斧。
2.2 容器宽度高度这个“隐形杀手”
柱状图画不出来,十个里有八个是容器尺寸的问题。Echarts初始化的时候会读取容器DOM的宽高,如果容器本身没有设置尺寸,或者是在CSS还没加载完的时候就执行了初始化,Echarts会直接警告“Can't get DOM width or height”,图表画出来是一团空白或者只有默认的100像素高。
这个问题在Vue里尤其常见。如果在mounted钩子里初始化图表,而容器的宽度依赖于某个异步加载的数据(比如父组件的布局还没撑开),就会初始化失败。我建议的做法是:容器写死min-height,样式上给一个明确的高度值;初始化时机放在DOM渲染完成且布局稳定之后;如果容器宽度可能变化(比如响应式布局),一定要监听resize事件并调用chart.resize()方法。还有一个容易被忽略的点:display:none的容器初始化后拿不到宽高,等容器显示出来的时候图表仍然不显示,需要手动触发一次resize。
3. 从零绘制第一个柱状图:option配置逐项拆解
3.1 一个最简柱状图长什么样
先给出一个最经典的入门示例,网上绝大多数教程,包括Echarts官方示例,用的都是这个结构,几乎所有可视化在线课程的第一关也是这样。代码层面很简单:一段HTML放容器,一段script初始化,然后setOption。option对象里,xAxis配置类目数据,series配置柱子的数值和类型。这段代码跑起来后,你就能在浏览器里看到7根竖直的柱子,分别对应一周七天的销量。
但我要提醒的是,不要满足于“看到图了”。这个看似简单的配置里,其实有四个默认机制在悄悄生效:Echarts会自动为坐标轴生成刻度、自动设置y轴的起始值为0、自动分配柱子的颜色(默认是不同深浅的蓝色系)、默认启用tooltip。这些默认行为,在简单demo里是方便的,在真实业务里往往是需要调整的。
3.2 xAxis、yAxis、series三者是如何关联的
这一节把三者关系理清楚,后面调样式才不迷糊。
xAxis(x轴)在直角坐标系里用于定义类目轴。它的type为category时,data数组就是各个类目的名称序列。series(系列)中的data数组则是数值序列,这两者通过数组下标一一对应:xAxis.data[0]对应series.data[0],xAxis.data[1]对应series.data[1],以此类推。这也就是如何把“第1关:Echarts中柱状图的绘制”里那种最简单的练习升级为“鼠标点哪儿在哪儿显示柱状图”这类交互功能的基础——因为你知道了数据与坐标轴的一一映射关系,就能通过事件对象拿到当前点击的类目下标,重新设置数据来完成动态展示。
yAxis(y轴)默认是数值轴,type为value,它会根据series里的数值范围来自动计算刻度。这里有一个我在实际项目中反复被设计师挑战的点:y轴起始值。Echarts默认从0开始,这符合图表道德规范,不夸大差异,但如果数据的数值范围很大(比如从10000到50000),柱子之间的高度差异看起来会很不明显。有些需求方会希望把y轴起点调整到最小值的整数位附近来“放大”差异,我会建议在保证不误导的前提下,通过min属性显式控制,而不是接受默认值,这样既能突出业务重点,又不违背可视化基本原则。
series是图表的灵魂组件,它的配置项最多也最灵活。type:'bar'声明了这是柱状图,name用于图例显示与联动,data是核心数据。除此之外,我常用的还有barWidth设置柱子宽度、barMaxWidth限制最大宽度、itemStyle配置柱子的颜色和圆角。前两个用于柱子的比例控制,第三个用于视觉美化。
3.3 让柱子“好看”起来:从默认样式到自定义视觉
默认的蓝色柱子虽然不算丑,但在业务项目里几乎不可能直接交付——要么得配合品牌色,要么得满足设计师对信息层级的要求。柱子样式的定制,主要围绕三个维度展开。
第一是柱子的颜色与描边。itemStyle.color控制填充色,可以是单一颜色,也可以是渐变色。渐变色的设置方式是传入一个对象,type为'linear',x、y、x2、y2定义渐变的起始方向,colorStops定义颜色分段。听上去有点抽象,你可以想象成在柱子表面拉了一条线,颜色沿着这条线从起点色过渡到终点色,调整四个坐标就能控制渐变的方向。这在实现“柱子从底部深色渐变到顶部浅色”这种大屏效果时非常常用。
第二是柱子圆角。borderRadius可以给柱子的四个角设置圆角值,常见做法是把顶部两个角的圆角值设大一些、底部两个角保持为0,形成类似数据报告里“胶囊柱”的视觉效果。圆角柱子看起来更精致、更有现代感,但在精确对比的场景里,直角柱子的视觉参考线更准确,设计师如果没明确要求,不必为了炫技而加圆角。
第三是柱子的宽度与间距。barWidth与barGap是一对配合使用的参数。当只有一个系列时,barGap没有意义;当有多个系列分组展示时,barGap控制的是组与组之间的间距,而同一组内不同系列的间距由barCategoryGap间接控制。我在项目里会通过barWidth显式指定柱子宽度,因为在大屏场景下,类目数量固定,不指定宽度时Echarts自动分配的间距在不同屏宽下会不一样,显示效果不稳定。
3.4 横向柱状图:一个配置项就能转方向
柱状图不只是竖直的,当类目名称特别长(比如部门名称、渠道名称)、或者类目数量很多时,横向柱状图往往是更合理的选择。Echarts里的实现方式是在xAxis中设置type:'value',在yAxis中设置type:'category',坐标轴类型互换,柱子就会横向排列。
这个“坐标轴互换”的思路很简单,但实际效果很好。我在做省份温度可视化这类与地域和指标结合的图表时,如果展示的是31个省份的某项温度指标,竖直柱状图需要把x轴文字旋转45度才能放下,可读性很差;改成横向柱状图后,省份名称在y轴上一字排开,数值轴在下方,阅读顺序很自然。横向柱状图还有一个额外优势:类目多的时候,可以配合dataZoom组件实现滚动查看,不牺牲图表区域的高度。
4. 进阶玩法:多系列柱状图与复合图表
4.1 堆叠柱状图与分组柱状图的应用差异
当数据包含不只一个维度时(比如各区域各产品线的销售额),单系列柱状图显然不够用。这里有两个方向:分组柱状图和堆叠柱状图。分组柱状图是把多个系列并列放在同一个类目下,适合比较不同系列之间的大小;堆叠柱状图是把多个系列在同一个类目下纵向累加,适合看总量以及各部分占总量的比例。
实现分组只需要在series里传两个对象,type都为bar,它们会默认并排显示。实现堆叠需要两个series中都设置stack为同一个值,这样它们就会“摞”到一起。我预判了大家会搜“origin柱状图叠在一起怎么分开”——如果你用的绘图工具是Origin,那里的拆分步骤是双击柱子调整“间距”和“重叠”值;但在Echarts里,你把stack属性删掉或者改成不同的值,堆叠的柱子就会自动变成分组并排显示。这个特性帮我解决过不少展示场景调整问题:先用堆叠看总量结构,汇报时临时改成分组看单项对比,一次配置两端兼顾。
4.2 柱状图叠加折线图:双Y轴的配合技巧
“柱状图叠加折线图”是业务里出现频率极高的组合图,大多是为了同时呈现两组量纲不同的数据,比如销售额(用柱子)和同比增长率(用折线)。两组数据的数值范围差得远——销售额是几千万,增长率是百分之几——如果共用一个y轴,柱子和折线总有一个会“被压扁”。这时候需要双y轴:柱子挂在左侧y轴,折线挂在右侧y轴。
Echarts里的实现方式其实很优雅。左侧y轴就是默认的yAxis,右侧y轴通过数组的方式声明第二个yAxis对象,用position:'right'放在右侧。series里的柱子不指定yAxisIndex(默认使用第一个),折线则设置yAxisIndex:1来绑定第二个y轴。这样两个系列各用各的坐标系,互不干扰。实操中的关键点是右侧y轴的起始值。折线对应的指标通常是百分比,默认从0到最大值可能显得折线角度太缓,我会结合业务需要手动设置min和max,让折线的波动幅度看起来更明显。
4.3 柱子上放图片、柱顶加文字:自定义系列怎么玩
有朋友问“echarts柱状图柱子可以用自定义图片显示不”,答案是可以,而且方式比想象中简单。柱子的底可以用图片填充:在itemStyle.color里设置type:'pattern',image是图片元素或URL,repetition设为'no-repeat',柱子表面就会铺上图片。我做过一个类似“产品销量榜”的页面,用产品缩略图作为柱子的填充纹理,效果远比纯色柱子生动。要注意的是,图片必须能跨域访问,否则canvas会将画布污染,导致图表无法导出。
柱子顶部加数值标签是另一个高频需求,直接配置label.show:true就行。需要注意position属性,竖直柱状图一般用'top',横向柱状图用'right',数值单位较大时用formatter函数格式化成“万”“亿”等单位。formatter是Echarts里相当实用的一个回调,支持字符串模板和函数两种写法,函数写法能拿到参数对象里的数据值、系列名、类目名,几乎可以做任何输出加工。
5. 真实项目的数据接入:异步加载、动态更新与tooltip优化
5.1 从静态数组到后端接口:ajax与fetch接入数据
教程里常画静态数据,真实项目几乎总是从接口拿数据。“将原生js、jquery、ajax、echarts结合制作网页”这个搜索词特别典型,说明很多人都在用这种前后端分离之前流行的组合方式。如果你用的是jQuery,直接在$.ajax的success回调里setOption就行;用现代fetch也一样,在Promise的then里处理。
我推荐把“获取数据”和“渲染图表”拆成两个函数。getData负责请求接口并把后端返回的数据映射成Echarts需要的xAxis.data和series.data格式,renderChart负责真正的图表渲染与更新。这样做的好处是数据格式变动时只需要改getData,不用碰图表逻辑。还有一个习惯值得培养:对后端返回的数据做清洗与校验。接口给的数据偶尔会有null、undefined,或者数值被存成了字符串,这些情况不处理,图表要么显示异常要么完全空白。加一道parseFloat和空值过滤,省去很多排查时间。
5.2 setOption的合并机制:动态更新数据的正确姿势
图表做出来以后很少是静态的,动态更新是常态。Echarts的setOption默认采用“合并模式”,新传入的配置项会和旧config做深合并,未变更的部分自动保留;如果传入第二个参数为true,则进入“全量替换”模式,整个option被新配置覆盖。初学时这一点特别容易踩坑:我做一个带定时刷新的图表时,每次都重新setOption完整配置,图表闪烁不说,状态还被重置。后来改成只更新series里的data,选项配置保持为静态引用,图表丝滑多了。
数据量变化时还有一个隐藏的坑:类目数量和柱子数量不一致时,旧图表中多出来的类目不会自动消失。如果数据是“每次从接口拉最新N条”,需要在使用setOption动态更新时候显式处理,把series的data清空或者把xAxis的data整体替换。还有一种做法是调用chart.clear()清空画布再重新setOption,但这样会丢掉实例上已有的状态(比如缩放范围),能少用就少用。
5.3 tooltip自动换行与格式化:细节影响体验
关于“echarts tooltip自动换行”的问题,网络上问的人特别多。tooltip内容是文本,如果series名称比较长,或者数值后面跟了很长的单位描述,默认显示会横向撑开,视觉效果很糟糕。Echarts的tooltip文本是支持HTML的,你可以在formatter返回的字符串里写
换行,也可以给tooltip设置宽度并让内容自动换行。
更专业一点的做法是使用formatter函数的返回值带HTML结构,做一个多行展示:第一行显示类目名称,第二行显示系列名和数值,必要时再配一个对比信息的第三行。高版本的Echarts里,tooltip的extraCssText属性允许注入额外的CSS样式的文本,配合backgroundColor和textStyle,可以做出与页面风格统一的提示框。tooltip的好坏直接影响图表的可用性,很多用户对可视化的印象,其实就来自鼠标悬停时的这个悬浮框做得是否细心。
6. 大屏场景下的柱状图实践:适配、优化与3D扩展
6.1 可视化大屏的尺寸适配问题:为什么pxtorem对Echarts无效
现在“可视化大屏”已经从企业的展示需求走向了更广泛的应用场景。做可视化大屏项目时,最头疼的问题之一就是适配。不同分辨率的屏幕,图表尺寸、字体大小、柱子宽度都要跟着变。很多项目用了rem方案,布局层面的CSS经过pxtorem转换后能自适应缩放,但到了Echarts这里就失效了——因为Echarts的图表是canvas绘制的,所有尺寸参数都以像素为单位写在配置项里,不经过CSS处理,所以pxtorem对echarts没起到效果是正常的。
大屏项目里我常用的适配方案是这样:在resize事件里使用当前屏幕宽度和前一个屏幕宽度的比值,重新计算全局的配置项标准尺寸。具体来说,把字体大小、柱子宽度、图表间距这些用rem做单位的配置放在一个对象里,在resize时通过换算重新计算并setOption。也可以反过来走更“暴力”但可靠的路线:直接用transform的scale对整个图表容器做缩放,用JS计算当前视口与设计稿的比例并应用到图表外层,这样图表内部不用动,成本很低。
6.2 大数据量柱状图的优化思路
当一次性要渲染上千根柱子时,图表性能会明显下降,操作时会有卡顿感。针对大数据的优化,我分享一个实际验证过有效的组合策略。先用sampling属性开启数据采样,Echarts内置了多个采样算法——比如lttb(保留趋势特征)——在数据量大的时候可以先降采样再绘制。然后关闭不需要的动画,animation:false,因为大数据量下动画不仅没有促进作用,反而拖慢渲染速度。最后优化坐标轴刻度,axisLabel的interval设为'auto',让系统自动跳着显示类目标签,避免一屏塞几百个标签导致文字重叠。经过这三步处理,万级数据的柱状图依然能保持一个相对流畅的交互体验。
6.3 3D柱状图与地图结合:拓展Echarts的能力边界
Echarts社区里能搜到“柱状图 3d echarts”的诉求,基础的Echarts库里本身不带3D柱状图能力,需要引入echarts-gl扩展。echarts-gl提供的bar3D系列可以在三维空间里绘制柱体,配合visualMap组件,可以在柱子的颜色维度上再编码一个数据维度,做出来的大屏视觉效果比普通的2D柱状图抢眼不少。不过我的态度是:3D柱状图适合数据少、展示需求强的场景,数据一多或者需要精确读数的场景,还是2D柱状图更合适——3D空间的透视会让柱子高度比较产生视觉误差,这一点需要提前跟业务方沟通清楚。
另一个拓展方向是“省份温度可视化”这类场景,把柱状图和中国地图结合,在地图上按省份做柱状标记。Echarts的两种实现思路是:用自定义系列在geo坐标系里画柱子,或者用地图系列的markPoint加上柱形标记。地图和柱状图的组合能同时表达“位置”和“数值”两个维度,是地理可视化里一个非常实用的套路,这个部分我准备在后续教程里单独展开,这篇先挖个坑。
7. 实测排查:柱状图项目里最常见的8个问题与处理方案
学Echarts的过程中,遇到报错和显示异常是很正常的,我把过往项目里最高频的问题整理成一个速查表,每个问题都写清楚现象、原因和处理方式,当你遇到图表不显示的时候可以按图索骥,直接照做就行。
| 问题现象 | 常见原因 | 解决方案 |
|---|---|---|
| 图表区域空白,控制台报Can't get DOM width or height | 容器未设置宽高,或初始化时容器不可见 | 给容器设置显式宽高,在容器显示后再初始化,必要时手动调resize |
| 柱子显示不出来但坐标轴正常 | series.type没写,或data是空数组 | 检查series.type是否为'bar',数据是否有值 |
| 柱子的颜色都一样,分不清系列 | series里缺少name或未设置不同颜色 | 给每个系列设置name,在series下用itemStyle.color区分 |
| 堆叠图想拆成并排却还是重叠的样子 | 多个series的stack属性相同导致错误堆叠 | 删除或将不同系列改为不同的stack值 |
| 动态更新数据后,多出来的旧柱子还在 | setOption合并模式下未替换xAxis.data | 更新时全量替换xAxis.data,或改用setOption(option, true) |
| 大屏缩放后图表变形或模糊 | 未监听resize事件或canvas未重绘 | 绑定window resize事件调用chart.resize(),或按缩放比例重算配置 |
| 鼠标悬停提示框内容过长,布局乱掉 | tooltip未换行、宽度未设置 | 在tooltip的formatter里加 ,并设置extraCssText的宽度和样式 |
| 柱子上显示数值时数字与柱子重叠 | label.position配置不当 | 竖直柱状图用position:'top',横向柱状图用position:'right' |
这个速查表基本覆盖了我做技术答疑时被问到最多的柱状图问题,建议配合官方文档的option查找页一起使用——Echarts的配置项确实多,宁可多查文档,也不要靠记忆堆配置。另外,“echarts社区”和官方示例库(makeapie等)里有很多现成的配置示例,遇到“不知道怎么配”的情况,先去看社区里别人怎么写的,往往比硬啃文档效率高得多。
最后分享一个我在实际使用中的个人习惯:任何柱状图项目,不管需求多简单,我都会顺手把grid的左右上下边距显式配置出来。这是因为默认的grid数值在展示长类目名或大数值时经常会挤占到容器的边缘,导致标签被截断。提前把边距和柱子的barWidth固定下来,相当于给图表加了一层“防呆设计”,能避免后面因为数据变化而导致布局焦虑。
另外,如果你正在学习Echarts,大可不必把官方API的每个配置项都背下来。我的建议是先熟练掌握今天讲的这些柱状图常用配置项,以及setOption、resize、on事件这三个实例方法,剩下的遇到问题现查现用。能用好柱状图,你就能覆盖工作中八成以上的可视化需求;把今天这些内容动手敲一遍,再结合你的数据改造出属于自己的图表,Echarts你也就算真正入门了。下一篇我打算聊聊折线图的绘制以及它与柱状图的组合实战,到时候见。