ARTICLE DETAIL

资讯详情

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

ECharts饼图中心文字添加全攻略:从原理到实战

ECharts饼图中心文字添加全攻略:从原理到实战 1. 项目概述为什么要在饼图中间加文字如果你用过ECharts画饼图大概率会遇到一个需求在饼图中间那块空白的区域放上一些关键的文字信息。这个需求太常见了比如展示一个项目的完成率中间放个“75%”展示销售占比中间写个“总销售额¥1,200万”或者就是一个简单的标题比如“2023年度业务分布”。这个看似简单的功能却让不少刚接触ECharts的朋友有点懵因为ECharts的配置项里并没有一个叫“饼图中心文字”的直白选项。我刚开始用的时候也是对着文档找了半天试了title、试了legend甚至想过用graphic组件画个文本框上去。后来才发现ECharts实现这个效果核心是对series系列配置项的深度理解和组合使用。它把“饼图”看作一个数据系列而这个系列本身就可以承载丰富的文本和样式配置。这其实体现了ECharts一个很好的设计哲学通过灵活的配置组合来实现复杂的视觉效果而不是提供无数个死板的开关。所以这篇内容我们就来彻底搞懂怎么优雅、灵活地在ECharts饼图中心添加文字。这不仅仅是写一行代码的问题我会带你理解背后的配置逻辑解决你可能遇到的各种细节问题比如文字怎么居中、样式怎么调、动态数据怎么更新以及如何避免那些我踩过的坑。无论你是想加静态标题、动态数据还是制作一个交互式的中心标签看完你都能自己搞定。2. 核心思路拆解饼图文字的“三层架构”要给饼图中间加文字不能只盯着一个地方。根据我的经验最清晰的做法是建立一个“三层架构”的思维模型。这样无论需求多复杂你都能快速定位到该修改哪个配置项。2.1 第一层series.label- 扇区标签的误区很多人的第一反应是修改series.label。这个配置项确实是用来在饼图的每个扇区上或旁边显示文字的比如显示每个分类的名称和百分比。但它的定位是扇区关联标签它的位置是相对于每个扇区来计算的。你可以通过position: inside让标签显示在扇区内部但即便如此这些标签也是分散在各个扇区里的无法汇聚到饼图的中心点形成一个整体的“中心文字”。注意试图用series.label并通过调整distance等参数把标签“拉”到中心是一个常见的错误尝试。这会导致当扇区大小变化时标签位置极其不稳定且无法实现真正的居中对齐代码也会变得难以维护。2.2 第二层series.title- 真正的“中心文字”担当这是实现中心文字功能的核心和正确入口。在饼图type: pie的series配置项下有一个title子配置项。这个title不是指整个图表的标题那个是顶层的title配置而是专属于这个饼图系列的一个“内部标题”。它被设计用来在饼图、环形图等中心区域显示文字。series.title提供了完整的控制能力text: 要显示的文字内容。subtext: 副标题通常显示在text下方。offsetCenter: 这是控制位置的关键它是一个数组[水平偏移量, 垂直偏移量]单位可以是像素如‘10’或百分比如‘30%’。设置为[0, 0]就是严格相对于饼图中心居中。textStyle/subtextStyle: 分别控制主副标题的字体、颜色、粗细等样式。为什么是它因为series.title的定位基准点就是饼图的中心点。无论饼图大小如何变化无论是否有环形半径radius它都能基于这个中心点进行偏移从而实现稳定、精确的居中控制。2.3 第三层graphic组件 - 终极自由度的备选方案如果你的需求非常特殊比如要在中心文字周围加一个自定义形状的背景或者要实现极其复杂的动画效果那么可以考虑使用graphic组件。graphic是ECharts的图形组件可以让你在画布的任意位置绘制矩形、圆形、文本等原生图形。你可以通过计算饼图容器的中心坐标然后用graphic画一个type: text的图形元素放在那里。这种方法自由度最高但也最繁琐。你需要手动计算位置并且当图表容器大小发生变化时例如浏览器窗口缩放你需要监听resize事件并重新计算位置否则文字会错位。实操心得对于95%的“饼图中心加文字”需求优先使用series.title。它是由ECharts内部托管和定位的响应式做得很好代码简洁维护成本低。只有当你需要突破series.title的样式限制时才考虑graphic方案。3. 基础实现与核心配置详解现在我们进入实战环节。我将从一个最基础的例子开始逐步添加细节让你看清每一个配置的作用。3.1 最简示例让文字出现在中心假设我们有一个展示操作系统市场份额的饼图我们想在中间加上“市场份额”四个字。option { title: { text: 2023年桌面操作系统市场份额, // 这是整个图表的标题在顶部 left: center }, tooltip: {...}, // 提示框配置 legend: {...}, // 图例配置 series: [ { name: 市场份额, type: pie, radius: 50%, // 饼图半径设为容器宽度一半的50% data: [ {value: 1048, name: Windows}, {value: 735, name: macOS}, {value: 580, name: Linux}, {value: 484, name: Chrome OS}, {value: 300, name: 其他} ], // 核心配置在这里 title: { text: 市场份额, // 显示在饼图中心的文字 left: center, // 水平居中于饼图区域注意不是整个画布 top: center, // 垂直居中于饼图区域 textStyle: { fontSize: 18, fontWeight: bold, color: #333 } } } ] };关键点解析series.title.left和series.title.top这里设置为‘center’意味着将这个标题元素在其父容器即这个饼图系列所占的绘图区域内水平和垂直居中。这是最常用的居中方式。radius: ‘50%’这决定了饼图的大小。中心文字title的定位是基于饼图的有效区域计算的所以它会自动位于这个“圆”的中心。两个title的区别一定要分清顶层的title图表标题和series里的title中心文字。它们是独立配置的。3.2 使用offsetCenter进行像素级微调left: ‘center’和top: ‘center’是宏观对齐。如果你需要更精细的控制比如希望文字向上偏移10个像素或者向右偏移5%就应该使用offsetCenter。series: [{ type: pie, ..., title: { text: 总访问量, subtext: 2748 次, // offsetCenter: [水平偏移, 垂直偏移] // 正值向右/向下负值向左/向上 offsetCenter: [0, -10], // 文字整体向上移动10像素 textStyle: { fontSize: 24, color: #5470c6 }, subtextStyle: { fontSize: 16, color: #91cc75, fontWeight: bold } } }]在这个例子里我们同时设置了主文字(text)和副文字(subtext)。offsetCenter: [0, -10]使得这两行文字作为一个整体相对于饼图中心点向上移动了10像素。这个调整在视觉上常常是必要的因为绝对的数学中心点对于人眼阅读来说可能会感觉稍微偏下一点向上微调后看起来更舒适。常见问题为什么我设置了offsetCenter但left/top设置好像没用了答案是offsetCenter的优先级高于left和top。当offsetCenter被设置时left和top配置会被忽略。ECharts会先根据left/top或默认位置确定一个基准点然后再用offsetCenter进行偏移。但通常我们直接只用offsetCenter来定位这样更直接。3.3 环形图南丁格尔玫瑰图中的中心文字环形图设置radius为数组如[‘40%’, ‘70%’]和南丁格尔玫瑰图设置roseType: ‘area’是饼图的常见变体。好消息是series.title在这些变体中完全适用定位逻辑不变。series: [{ type: pie, radius: [30%, 70%], // 内半径30%外半径70%形成环形 roseType: radius, // 设置为南丁格尔玫瑰图扇区半径与数值成正比 data: [...], title: { text: 核心指标, subtext: 环形图示例, offsetCenter: [0, 0], // 依然位于环形的中心 textStyle: { fontSize: 20 } } }]无论你的饼图是实心的、空心的还是像玫瑰一样绽放的series.title的定位基准始终是这个系列几何形状的中心。这是一个非常稳定和可靠的特性。4. 高级技巧与动态数据绑定基础功能会了我们来看看如何玩得更溜。在实际项目中中心文字很少是静态的它可能需要反映总和、平均值或者跟随用户交互而变化。4.1 动态计算并显示数据总和这是非常常见的需求饼图中间显示所有扇区数据的加总值。// 假设这是你的数据 const pieData [ {value: 1048, name: Windows}, {value: 735, name: macOS}, {value: 580, name: Linux} ]; // 计算总和 const total pieData.reduce((sum, item) sum item.value, 0); const option { series: [{ type: pie, data: pieData, title: { // 使用模板字符串动态设置文字 text: 总计\n${total}, textStyle: { fontSize: 18, lineHeight: 26 }, offsetCenter: [0, 0] } }] };这里的关键是利用JavaScript的计算能力在生成option配置对象之前先算出数据总和total然后通过ES6的模板字符串将其嵌入到title.text中。\n是换行符让“总计”和数值分成两行显示。4.2 实现交互式中心文字更新更进一步当用户点击图例legend隐藏或显示某个扇区时中心的总数也应该实时更新。这需要用到ECharts的事件和动态更新API。// 初始化图表 const myChart echarts.init(document.getElementById(main)); myChart.setOption(option); // 监听图例选择变化事件 myChart.on(legendselectchanged, function (params) { // params.selected 是一个对象记录了所有图例项当前是否被选中 // 例如{ ‘Windows’: true, ‘macOS’: false, ...} let newTotal 0; const seriesData option.series[0].data; // 遍历原始数据只累加当前被选中的项 for (let i 0; i seriesData.length; i) { const item seriesData[i]; // 如果该系列未被取消选中即显示状态 if (params.selected[item.name] ! false) { newTotal item.value; } } // 动态更新中心标题 myChart.setOption({ series: [{ title: { text: 当前总计\n${newTotal} } }] }); });避坑技巧在事件回调中更新option时最好使用setOption并传入一个只包含需要修改部分的配置对象而不是修改原始的option变量再整个setOption。ECharts会智能地合并这些更新性能更好。另外确保更新路径正确这里是series[0].title.text。4.3 富文本样式与自定义背景series.title.textStyle支持基础的样式。但如果你想要更花哨的效果比如文字阴影、渐变颜色或者给文字加一个圆角矩形背景就需要用到ECharts的富文本rich功能。title: { text: {a|总销售额}\n{b|¥ ${(total/10000).toFixed(2)}万}, textStyle: { fontSize: 16, rich: { a: { // 对应 {a|...} 中的样式 fontSize: 20, fontWeight: bold, color: #fff, backgroundColor: #5470c6, // 文字背景色 padding: [5, 10], // 内边距 borderRadius: 4 // 圆角 }, b: { // 对应 {b|...} 中的样式 fontSize: 28, fontWeight: bolder, color: #fac858, textShadow: 1px 1px 2px rgba(0,0,0,0.5) // 文字阴影 } } }, offsetCenter: [0, 0] }在这个例子中text属性里使用了{样式名|文字内容}的语法来定义富文本片段。在textStyle.rich对象中为a和b分别定义了复杂的样式包括背景、内边距、阴影等。这样就能实现高度定制化的中心文字视觉效果而无需动用更复杂的graphic组件。5. 常见问题排查与解决方案实录即使理解了原理在实际编码中还是会遇到一些“诡异”的问题。下面是我总结的几个典型场景和解决办法。5.1 问题一文字不显示或位置不对这是最常遇到的问题可能的原因和排查步骤检查配置项路径确认你把title写在了series数组里某个系列对象的下面而不是和顶层的title搞混了。路径应该是option.series[0].title。检查饼图半径radius如果radius设置得非常大例如‘100%’饼图可能会撑满容器导致中心区域视觉上很小甚至不存在文字可能被挤到外面看不见。尝试将radius调小比如‘70%’。检查offsetCenter值如果你用了offsetCenter并且偏移量特别是百分比偏移设置得过大文字可能被移出了绘图区域。先用[0, 0]测试。检查容器宽高确保你的图表容器div有明确的宽度和高度。如果容器高度为0图表无法渲染文字自然不显示。浏览器开发者工具检查打开浏览器的开发者工具F12检查图表对应的Canvas或SVG元素看看title对应的DOM元素或图形是否被生成它的坐标属性是否异常。5.2 问题二文字样式不生效现象设置了color,fontSize但没变化。排查确认样式是写在series.title.textStyle里而不是series.title的直接属性下。同时检查是否有更高优先级的全局样式如通过CSS覆盖了它。注意如果使用了富文本rich那么定义在textStyle根级别的color、fontSize可能不会作用于富文本片段必须在rich的每个子样式里单独设置。5.3 问题三环形图内半径太大文字空间不足现象环形图radius设为[‘70%’, ‘90%’]中间空心部分很小文字显示不全或很拥挤。解决方案调整内半径减小内半径的第一个值例如改为[‘50%’, ‘90%’]给中心留出更多空间。调整文字大小根据内半径大小动态计算字体大小。这是一个更高级的技巧。const innerRadius ‘60%’; // 假设内半径百分比 const fontSize parseInt(innerRadius) * 0.8; // 一个简单的比例计算 title: { text: ..., textStyle: { fontSize: fontSize // 动态字体大小 } }简化文字内容如果空间实在有限考虑只显示最关键的数字去掉冗长的标题。5.4 问题四多饼图场景下的中心文字定位当你有多个饼图系列series数组中有多个对象时每个饼图都有自己的title配置它们会分别定位在各自饼图的中心。series: [ { // 系列1 type: pie, center: [25%, 50%], // 第一个饼图放在左侧 radius: 40%, data: [...], title: { text: 第一季度, offsetCenter: [0, 0] } }, { // 系列2 type: pie, center: [75%, 50%], // 第二个饼图放在右侧 radius: 40%, data: [...], title: { text: 第二季度, offsetCenter: [0, 0] } } ]在这个例子中两个饼图通过center属性分别定位在画布的左半部分和右半部分。它们各自的series.title则会准确地显示在各自饼图的中心位置。理解center和title定位的独立性是关键。6. 性能优化与最佳实践当图表变得复杂或者需要频繁更新时一些好的习惯能避免性能问题和奇怪的bug。避免在动画中频繁更新title如果你为数据变化设置了动画animation: true同时又在动画过程中高频调用setOption更新中心文字比如在定时器里可能会导致动画卡顿或文字闪烁。可以考虑在动画开始前或结束后再更新文字。使用notMerge参数要谨慎myChart.setOption(newOption, false)第二个参数为false表示不合并旧配置这会清空图表。除非你需要完全重置图表否则在更新中心文字时应该使用默认的合并模式或不传第二个参数。对于超多数据点的饼图饼图不适合展示过多分类建议不超过10个。如果分类太多中心文字区域可能会被密集的扇区标签干扰。此时可以考虑将小比例数据合并为“其他”项。隐藏扇区标签label: { show: false }让视觉焦点更集中在中心文字和整体比例上。响应式设计的考虑如果你的图表容器大小会随着页面布局变化ECharts默认会很好地处理series.title的重新定位。你只需要确保在window.resize事件时调用myChart.resize()即可。如果你用的是graphic方案则必须自己手动在resize事件回调中重新计算并更新文字位置。7. 替代方案使用graphic实现绝对定位文字虽然series.title是推荐方案但了解graphic作为备选方案是有必要的。以下是一个简单示例用于在特定场景下例如需要将文字定位在相对于整个画布的某个固定位置作为参考。option { // ... 其他配置如tooltip, legend, series... graphic: { type: text, // 类型为文本 left: center, // 相对于整个画布水平居中 top: 50%, // 相对于整个画布垂直居中50%位置 style: { text: 这里是中心文字, fontSize: 20, fill: #333 // 填充色 }, // 如果需要根据饼图中心动态计算可以这样 // position: [myChart.convertToPixel(grid, [50, 50])[0], myChart.convertToPixel(grid, [50, 50])[1]] } };使用graphic的注意事项定位基准不同graphic的left/top默认相对于整个图表容器而series.title相对于系列自身区域。要将graphic文字对准饼图中心需要复杂的坐标转换使用convertToPixelAPI代码更复杂。无自动响应图表resize时graphic元素的位置不会自动更新除非你手动监听resize事件并重新计算位置。维护成本高逻辑分散不如series.title那样与饼图数据系列紧密耦合。因此再次强调除非有非常特殊的、series.title无法满足的定制化样式需求否则请坚持使用series.title。在我多年的前端和数据可视化开发经验里ECharts的series.title是处理饼图中心文字最优雅、最稳定的方案。它把复杂度封装了起来提供了直观的配置接口。从简单的静态标签到复杂的动态交互它都能胜任。关键是要建立起“系列私有标题”这个概念并善用offsetCenter进行微调。下次当你需要在饼图中间加点什么的时候别再四处寻找那个不存在的“centerLabel”配置了直接打开series.title你会发现它早已为你准备妥当。
返回列表