news 2026/9/29 3:02:55

Echarts饼图配置详解:从基础绘制到常见问题避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Echarts饼图配置详解:从基础绘制到常见问题避坑指南

算上这篇,Echarts可视化教程已经写到第四篇了。前几篇咱们从基础的柱状图起步,聊过坐标轴的刻度处理,也碰过折线图里tooltip的换行问题,这次轮到饼图。饼图在数据可视化里的地位很特殊——它不像柱状图那样适合精确比较,也不像折线图那样适合看趋势,它最擅长的是表达占比关系,也就是“谁占了多大份额”。电商后台的类目销售占比、用户画像里的流量来源分布、大屏上的设备状态统计,这些都是饼图的高频使用场景。

这篇博客我会围绕Echarts饼图,把基础的series配置、标签布局、数据更新这些核心点全部过一遍,然后结合完整示例演示如何绘制、如何调整、如何避坑。文中用到的数据和代码,都以一个模拟的“二季度各品类销售额占比”为背景来说明,方便直接复用。

1. 饼图绘制的整体设计与思路拆解

1.1 饼图在数据可视化中的适用场景

饼图这类图形,本质是把一个整体切成几块扇形,每一块的比例对应某个分类的数值占比。它的优点一眼就能看出来——直观,小学生也能看懂,适合快速传递“谁最大、谁最小、差距明显不明显”这类信息。但它的劣势同样突出:当分类太多(超过8个)、或者各项比例非常接近的时候,人眼很难通过扇形角度去判断精确大小,被切得密密麻麻的“千层饼”会让阅读者崩溃。

所以,我一般在下面几种情况下才会用饼图:

  • 分类数量在3到7个之间,最多不超过8个。
  • 数据总和可以作为“整体”去理解,也就是100%有意义,比如预算分配、流量来源。
  • 重点是看比例结构,而不是精确数值对比。
  • 目标读者需要快速建立直观印象,不花时间看详细数字。

如果数据量太大或者需要看趋势、看精确排序,我建议老老实实改用柱状图或者条形图。这个选型思路在教程第一篇里就强调过,图表选型和写代码一样重要,选错图等于白做。

1.2 从柱状图理解到饼图的思路迁移

柱状图的坐标轴思维是“数值轴+类目轴”,填入data之后,x轴每个类目对应一根柱子。饼图则完全不同——它没有传统坐标轴,核心是series中的type: 'pie'。

我们只需要把数据组织成一个数组,每个数组元素包含name和value两个字段,然后传给series。Echarts会自动计算每个值在总和中的占比,然后绘制出对应的扇形。

option = { series: [{ type: 'pie', data: [ { name: '数码家电', value: 453 }, { name: '服饰鞋包', value: 312 }, { name: '美妆个护', value: 289 }, { name: '食品生鲜', value: 176 }, { name: '家居百货', value: 98 } ] }] };

就这么简单,一段最基础的饼图代码就完成了。但是实际项目里很少只满足于“能显示”,我们通常要调整半径、设置颜色、加上百分比标签、制作环形图、处理图例遮挡、让tooltip格式化得更友好。这些都属于配置项层面的操作,接下来一步步展开。

2. 核心配置项解析与绘制原理

2.1 基础配置:series-pie的必备参数

在Echarts中,饼图的所有核心行为都由series中的pie系列控制。常用的配置项整理如下:

配置项类型默认值作用说明
typestring必填固定为'pie'
namestring无系列名称,用于tooltip和图例
radiusnumber/string/array['0%', '75%']饼图半径,可写百分比或像素值
centerarray['50%', '50%']圆心位置,第一个是横坐标,第二个是纵坐标
dataarray无数据项数组,核心内容
roseTypestring/booleanfalse是否显示为南丁格尔玫瑰图
labelobject无标签文本配置,控制名称和数值的显示
labelLineobject无标签引导线配置
itemStyleobject无每个扇区的样式,颜色、边框等
emphasisobject无高亮状态配置,鼠标移到扇区时的样式

先说radius。它有两种用法:传单个数值或百分比,表示普通饼图半径;传数组[内半径, 外半径],就会生成环形图(也叫环形饼图、圆环图)。很多人做看板时喜欢用环形图,因为中间那块空出来的区域可以放总数、核心指标或者一张小图,视觉上更有层次。

radius: ['40%', '70%']

这行配置生成的就是内半径40%、外半径70%的环形图。为什么用百分比而不是像素?因为百分比是相对于容器宽度和高度中较小值计算的,可以自动适配不同屏幕尺寸,尤其是做大屏展示时,这一条非常重要。

再说center。默认是['50%', '50%'],也就是容器正中。如果你在做一个看板,饼图旁边还要放几个KPI数字,可以考虑把饼图往左偏一点,右侧留出空间放统计文本。

center: ['35%', '50%']

2.2 颜色控制:调色盘与itemStyle

Echarts里控制颜色的方式主要有三种,优先级从低到高分别是:全局color调色盘、系列级color、单个数据项里的itemStyle.color。

全局调色盘定义了一组默认颜色,当饼图扇区没有单独指定颜色时,Echarts会依次从调色盘中取色:

color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4']

如果想针对某个数据单独指定颜色,直接在这个数据项里写:

data: [ { name: '数码家电', value: 453, itemStyle: { color: '#2f7ed8' } }, { name: '服饰鞋包', value: 312, itemStyle: { color: '#8dbbc4' } } ]

项目里如果视觉风格统一,我一般用全局调色盘搞定。如果某个扇区需要突出(比如监控大屏上某个指标异常),那就单独给这一项指定一个高亮色,配合emphasis还可以做得更细致。

2.3 扇形样式:边框、透明度与高亮

扇区本身的一些细节可以通过itemStyle来控制。常用的几个属性:

  • borderRadius:扇区圆角,适合做那种圆润风格的卡片式大屏。
  • borderColor:扇区边框颜色,通常设置成和背景同色,这样扇区之间会有间隙感。
  • borderWidth:边框宽度,间隙感就是通过它实现的。
  • opacity:整体透明度。

emphasis控制的是鼠标悬停或者选中时的状态。比如悬停时让扇区高亮,可以设置scale配合label的样式:

emphasis: { scale: true, scaleSize: 8, itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.4)' } }

scale是Echarts 5.x版本里比较实用的一个新特性,悬停时扇区会轻微放大,提示感非常自然。不过要注意,scale在roseType开启时配合使用的效果好,普通饼图也很不错。

3. 标签、图例与tooltip的联动配置

3.1 label标签布局与引导线

饼图不像柱状图自带坐标轴注释,它的数据信息主要靠label和labelLine呈现。默认情况下,label显示在扇区外侧,由一根曲线引导过去。

label: { show: true, formatter: '{b}: {d}%', fontSize: 12 }

formatter支持模板字符串,其中{b}是名称、{c}是数值、{d}是百分比。'{b}: {d}%'的含义就是“分类名: 百分比”,例如“数码家电: 33.4%”。这是最常见的格式。

如果扇区比较小,标签文字会被挤在一起。我的习惯是把label位置设置成outside并在labelLine上做调整,同时配合minShowLabelAngle使用。这个配置也很关键:

minShowLabelAngle: 3

意思是小于3度的扇区不显示标签,避免一堆姓名和百分比糊成一团。

labelLine控制的是引导线样式。Echarts提供的默认引导线由三段组成:水平线、斜线、末尾的圆点。很多人会遇到曲线和圆点偏移的问题,大多是因为label的宽度或者文字长度溢出,导致引导线的端点位置计算出现了异常。最直接的解决方法是留出足够的grid边距,或者在富文本模式下手动指定label.width。我们下一部分专门讲这个问题。

3.2 legend图例的显示与交互

饼图的legend默认显示在顶部,可以点击图例项来隐藏对应的扇形。这个交互本身是Echarts自带行为,不需要额外写事件。

常用配置是设置orient和left/top来控制图例的摆放位置。做环形图时,我更喜欢把图例放到右侧垂直排列,这样视觉重心更平衡:

legend: { orient: 'vertical', left: 'right', top: 'middle' }

formatter也可以用来给图例增加一些说明,比如在名称后面补充数值信息。需要注意:legend的data不一定要显式声明,Echarts会自动从series的name字段里收集。如果项目中需要把某些类目从图例中移除,那再手动指定data数组。

3.3 tooltip提示框与自动换行

“Echarts tooltip自动换行”是搜索热词里排名很靠前的一个,可见大家在这上面踩坑不少。饼图的tooltip默认是鼠标放在扇区上时显示一个浮层,内容是系列名、数据名和数值。

先看一个基础配置:

tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)' }

这里{a}是系列名,{b}是数据项名称,{c}是数值,{d}是百分比。<br/>是H5的换行标签,Echarts的tooltip默认支持HTML渲染,所以直接用它就可以实现多行显示。

最常见的问题场景是:名称和数值太长了,不换行全都挤在一行,超出屏幕边界就会被截断。两种解决办法:

  • 调整tooltip的confine: true,让浮层显示在图表容器内部,不被外部遮挡。
  • 在formatter里手动拼接换行符<br/>,把长文本拆成多行。

比如遇到某个商品名称特别长,我的习惯是截断并加省略号:

formatter: function(params) { var name = params.name.length > 10 ? params.name.slice(0, 10) + '...' : params.name; return name + '<br/>' + '销售额: ' + params.value + ' 万元<br/>' + '占比: ' + params.percent.toFixed(1) + '%'; }

注意formatter既支持字符串模板,也支持回调函数。回调函数里能拿到完整的params对象,自由度更高。上面这段就是先把名称截断到10个字符,再拼接换行输出,多行信息一目了然。

4. 完整实操:从数据到可交互的销售占比饼图

4.1 项目准备与数据准备

假设我们现在拿到一个模拟数据,是某电商平台二季度各品类销售额(单位:万元):

品类销售额占比
数码家电45332.7%
服饰鞋包31222.5%
美妆个护28920.8%
食品生鲜17612.7%
家居百货987.1%
其他584.2%
合计1386100%

我直接用原生HTML + Echarts CDN做演示,因为教程的重点在配置项,不是工程脚手架。项目前期如果用npm管理依赖,也可以直接:

npm install echarts

然后按需引入:

import * as echarts from 'echarts';

演示就用CDN方式,能在浏览器里直接跑起来:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Echarts饼图实战</title> <style> #chart { width: 700px; height: 500px; margin: 40px auto; } </style> </head> <body> <div id="chart"></div> <script src="https://fastly.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> <script src="./pie.js"></script> </body> </html>

4.2 基础饼图的一步步实现

在pie.js里先初始化图表:

var chartDom = document.getElementById('chart'); var myChart = echarts.init(chartDom); var option = { color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#9a60b4'], title: { text: '二季度各品类销售额占比', subtext: '数据来源:模拟数据', left: 'center' }, tooltip: { trigger: 'item', formatter: '{b}: {c} 万元 ({d}%)' }, legend: { orient: 'horizontal', bottom: 10 }, series: [{ name: '销售额占比', type: 'pie', radius: ['0%', '70%'], center: ['50%', '50%'], data: [ { name: '数码家电', value: 453 }, { name: '服饰鞋包', value: 312 }, { name: '美妆个护', value: 289 }, { name: '食品生鲜', value: 176 }, { name: '家居百货', value: 98 }, { name: '其他', value: 58 } ], label: { formatter: '{b}\n{d}%' }, labelLine: { length: 20, length2: 10 } }] }; myChart.setOption(option);

这里每行配置都值得讲一讲。radius: ['0%', '70%']写的是数组形式,但内半径是0%,所以看起来跟普通饼图没区别。label的formatter用了{b}\n{d}%,\n在label的formatter中是有效的换行,这跟tooltip里用<br/>不一样。很多新人在两个场景里混用,结果标签不换行,这里要注意区分。

labelLine的length控制引导线中靠近标签的横线段的长度,length2控制斜线段的长度。如果标签文字离扇区太远或者太近,调整这两个值就行。

4.3 转换为环形图与玫瑰图

环形图的实现非常简单,就是把radius的内半径置为一个大于0的值:

radius: ['45%', '70%']

内半径45%外半径70%,这样就生成了一个标准的环形图。环形图中间那部分空出来的位置,可以用来写汇总指标。这里用title中的text和subtext来模拟就好:

title: { text: '总销售额\n1386万元', subtext: '', left: '34%', top: '42%', textAlign: 'center' }

把这个title跟环形图组合,中间正好填上总数,这是很多数据大屏的标准布局。

南丁格尔玫瑰图则是另一种视觉上更“炸”的饼图变体。开启方式很简单:

roseType: 'radius'

也可以用roseType: 'area'。两者的区别是:'radius'模式半径和数值成正比,扇区面积会由于半径差异更加夸张;'area'模式半径相同,但通过改变角度和面积来区分数值。视觉上,玫瑰图能在分类较多的时候提高区分度,但如果数值差距不大,反而容易误导读者。我的经验是,演示汇报时可以用玫瑰图提高观感,正式的数据报告尽量别用。

4.4 数据动态更新与动画处理

实际业务中的图表,数据不可能一成不变。有时要定时刷新,有时要再拉取新接口。Echarts在数据更新上做得特别方便——重新setOption即可,不需要销毁重建实例。

setInterval(function() { var newData = [ { name: '数码家电', value: Math.round(Math.random() * 500) }, { name: '服饰鞋包', value: Math.round(Math.random() * 350) }, { name: '美妆个护', value: Math.round(Math.random() * 300) }, { name: '食品生鲜', value: Math.round(Math.random() * 200) }, { name: '家居百货', value: Math.round(Math.random() * 120) }, { name: '其他', value: Math.round(Math.random() * 80) } ]; myChart.setOption({ series: [{ data: newData }] }); }, 3000);

注意一个关键细节:如果series数组是多个图表配置,比如一个页面里既有饼图又有柱状图,那么在更新数据时最好用setOption的第二个参数控制合并逻辑。默认是“增量替换”,同名的组件和系列会更新,不存在的会新增。这里只改data,其他配置比如radius、label都不动,什么都不会乱。

如果你在开发vue/react项目,还需要注意组件销毁时要把实例一起dispose掉:

myChart.dispose();

否则容易造成内存泄露。这个在“数据可视化大屏”场景里尤其重要,页面切来切去,实例越积越多,最后卡到爆。

5. 常见问题与排查技巧实录

5.1 高频问题速查表

问题现象可能原因解决办法
饼图只显示一个扇区,其他黑乎乎一片容器宽度或高度为0,或者多个series写错了检查<div>尺寸;确认series是数组
标签文字重叠、引导线乱飞扇区太小或标签太多设置minShowLabelAngle,或改用label.layout: 'none'
图例太多,底部都放不下分类数量太多把legend改为type: 'scroll'滚动模式
tooltip被容器边缘截断浮层超出了外层容器添加confine: true
labelLine末尾的小圆点偏移这是Echarts 5.x版本常见bug升级到5.5.x,或者关闭emphasis中label的特殊处理
饼图在整个页面里不居中center设置成了像素值,没跟随容器自适应改成百分比,比如['50%', '50%']
数字是string类型,计算占比全错数据源里value字段是字符串数据清洗,转成Number

5.2 那些年我踩过的饼图阴影坑

第一个坑是labelLine小圆点偏移。它在热词里反复出现,说明遇到的人不止我一个。这个问题的表现是:引导线末端的圆点落在了一个奇怪的位置,和文字对不齐。我排查过的原因有两种——

一是Echarts版本太老,5.0到5.2之间的版本确实存在一些label布局计算的小问题。最简单的解法是升级到5.5.x,很多bug在5.3之后的版本修复了。

二是emphasis状态下的labelLayout或label配置干扰了正常渲染。如果你没有特殊需求,建议这样写:

emphasis: { scale: true, label: { show: true, formatter: '{b}: {d}%' } }

而不是在highlight的时候去动态修改标签的位置。动态修改位置一旦取消高亮,位置没有恢复原状,小圆点就会“离家出走”。

第二个坑是数据中value为0的扇区。Echarts对value为0的扇区不会绘制扇形,但会保留图例和标签,结果就是图例里有一项,图上却找不到对应区域。你需要在数据处理时过滤或者置为极小值(比如0.01),或者不传给Echarts。

第三个坑出现在更新数据时动画被无限触发。如果你在setOption时不带notMerge参数,默认会以merge方式和新option做合并。这个行为大部分时候是符合预期的,但当你更新series的data时,旧的数据项比新的多,Echarts会保留多余数据并产生“幽灵扇区”。解决方案很简单:

myChart.setOption({ series: [{ data: newData }] }, true);

第二个参数传true强制不合并,旧的series直接替换成新的,不会留下多余项。

5.3 如何做自适应和大屏适配

数据大屏是Echarts的高频场景,而大屏的尺寸往往是不固定的。要让饼图跟着容器走,最简单有效的方案是监听resize事件:

window.addEventListener('resize', function() { myChart.resize(); });

如果页面里有多个图表实例,建议做一个统一的管理方法,容器变化时全部调用resize()。

如果你用的是flex布局,图表容器初始width为0,等页面渲染完成后再初始化图表也可能导致扇形比例错乱。一个实用的做法是使用nextTick或者在容器宽高计算完毕后再init,同时给容器设置一个最小宽高。

6. 从基础饼图到数据大屏的进阶方向

饼图画到这一步,你已经能处理最常见的业务需求了。接下来有几个非常自然的延伸方向,我在实际做项目时经常用到。

第一个是图表联动。比如一个销售看板,左边放饼图展示品类占比,右边放柱状图展示每个品类的子类目销售额。点击饼图的某个扇区时,柱状图自动刷新成对应品类的数据。Echarts通过myChart.on('click', function(params) {...})暴露了点击事件,参数里有params.name,这个值就是扇区对应的分类名。

myChart.on('click', function(params) { if (params.componentType === 'series') { // 通过 params.name 刷新其他图表 updateBarChart(params.name); } });

第二个是用富文本标签做更高的自定义程度。Echarts的label支持rich字段,你可以在里面定义各种样式,比如百分比想放大、名称想加粗、颜色想区分,都能做到。之前搜热词里有“echarts饼图labelline末尾小圆点偏移”,其实很多时候是因为复杂富文本标签导致引导线布局算错,这时候可以先简化rich配置,排查出具体原因再逐项加回来。

第三个是把饼图和地图结合。热词里也出现了很多“echarts中国地图”相关的搜索。地图加饼图是比较经典的地图可视化方式:地图上每个省份的标记点用一个小饼图展示该省份的各类别占比。做法上,通常是散点图用coordinateSystem关联地图坐标系,然后通过symbol或custom系列绘制小型的饼图。这个以后如果有机会,我可以单独开一篇来讲。

第四个是饼图在vue/react项目里的使用。vue-echarts和echarts-for-react这两个封装库都很好用。以vue为例,核心是注意响应式数据的更新和组件销毁时的实例清理。热词里有一条“pxtorem 对echarts没起到效果 vue3”,这个多半是单位换算的坑。Echarts的内部尺寸读取自容器元素,如果你的页面开启了rem适配,但容器的font-size或者宽度没有正确换算,图表就会异常。建议在图表初始化前先确保容器尺寸已经按rem换算完成。

最后再分享一点个人经验

饼图这套配置项我反复用过几十次,最深的体会是:Echarts的配置项其实是分层递进的。先从series和data跑通一个能看的图,再去优化label、tooltip、legend,最后才考虑动画和交互。很多人一上来就把官方示例里几十行的复杂配置复制过去,改半天改不出效果,其实就是因为没搞清哪些配置控制什么、优先级怎么排。

我个人的流程一直是:“先输出,再美化,后交互”。输出指的是数据对、图能画出来;美化指的是颜色、标签、间距、引导线这些视觉细节;交互指的是点击事件、联动、钻取。按这个顺序走,饼图基本不会出大问题。希望这篇教程能帮你少走一些弯路。

如果后续遇到某个具体报错,或者某段配置怎么调都不生效,欢迎在评论里带上你的配置片段,我看到都会回复。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 3:02:16

基于MATLAB GUI的FIR数字降噪器设计与窗函数对比实现

1. 项目背景与设计思路夏天最烦人的声音&#xff0c;大概就是窗外那一片没完没了的蝉鸣。高频、持续、穿透力强&#xff0c;你关窗都能听见。我一开始想用耳机主动降噪&#xff0c;但转念一想&#xff0c;与其靠硬件&#xff0c;不如直接在信号处理层面把这个问题干掉——用MAT…

作者头像 李华
网站建设 2026/9/29 3:01:57

PostgreSQL增删改核心语法与进阶实战:INSERT/UPDATE/DELETE

1. 为什么我建议先把增删改彻底吃透1.1 这篇教程的定位与前置基础说句实在话&#xff0c;PostgreSQL 入门最容易被高估的是 SELECT&#xff0c;最容易被低估的是 INSERT、UPDATE、DELETE 这一组增删改操作。SELECT 写错了大不了重查一次&#xff0c;但插入、更新、删除这三条语…

作者头像 李华
网站建设 2026/9/29 3:01:08

OpenClaw 3.8升级实战:解决session锁与npm/Yarn混装问题

我的 OpenClaw 升级实战系列第二篇来了。这次记录的是把 OpenClaw 从 3.6.x 一路升级到 3.8 正式版的完整排障过程。和第一篇讲干净部署不同&#xff0c;这次我的开发机环境相当乱——npm 和 Yarn 混着装&#xff0c;全局包和项目包互相打架&#xff0c;session 文件被锁到超时…

作者头像 李华
网站建设 2026/9/29 3:01:07

网营科技与阿里千问办公于云栖大会达成AI战略合作,共话生态协同

9月23日&#xff0c;网营科技与阿里千问办公于2026云栖大会现场正式签约&#xff0c;达成AI战略合作。双方将结合千问办公深度打通钉钉生态的组织协同与AI生产力优势&#xff0c;以及网营科技在品牌电商领域的自研Agent与业务应用经验&#xff0c;共同探索AI在企业与电商高频业…

作者头像 李华