尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ECharts词云图开发实战:插件配置、数据清洗与性能调优

ECharts词云图开发实战:插件配置、数据清洗与性能调优 简介一份面向前端开发者的 ECharts 词云图完整示例与配置解析资源主要解决开发者在使用 echarts-wordcloud 插件时遇到的引入库、数据格式编排和样式参数调优问题适合数据可视化初学者和需要快速落地词云图功能的前端工程师。示例从最简单的 demo 入手展示了从准备 name/weight 结构的数据、初始化图表到 setOption 渲染的完整流程并对 shape、sizeRange、rotationRange、grid、textStyle.color 等关键参数逐项说明方便读者理解每个配置项的作用。压缩包共 6 个文件大小 233KB包括 3 个 JavaScript 脚本、1 个 HTML 示例页面、1 张效果预览图以及 1 份使用说明文档文件结构清楚可以直接打开运行并对照修改。目前已有 11883 人浏览学习说明该示例具备较强的参考价值。通过这份资料读者可以快速掌握词云图的实现思路自由调整文字大小、旋转角度、配色和整体布局为后续做更复杂的数据可视化页面打下基础。1. 词云图不是 ECharts 开箱功能核心版不带你得自己拼ECharts 主库从 2.x 到 5.x 内置了柱状图、折线图、饼图、地图、热力图这些常规系列但词云图始终没有进过核心包。你需要额外引入echarts-wordcloud.js这个插件才能让series[0].type wordCloud被识别。很多人在这一步倒过从 CDN 拉了最新的echarts.min.js又照着网上的旧教程塞了echarts-wordcloud.js页面直接报Cannot read property getZr of undefined。这不是你代码写错了是主库版本和插件版本错位。下面我用一份完整的词云图 demo 包把文件依赖、配置参数、数据预处理和常见坑全部过一遍适合做数据可视化报表、舆情分析页面或者面试前突击 ECharts 定制系列的人。2. 拆包分析从文件清单到加载顺序的依赖链2.1 四个核心文件的职责划分资源包里一共有index.html、js/echart3.js、js/jquery-1.9.1.min.js、js/echarts-wordcloud.js、使用说明.txt、示例图.jpg这几个文件。其中三个 JS 文件的分工必须清楚echart3.js是 ECharts 3.x 的主库负责画布渲染、坐标系、组件调度echarts-wordcloud.js是在主库之上注册wordCloud系列类型的插件它内部调用主库的echarts.extendSeriesModel、ChartView等扩展接口jquery-1.9.1.min.js在本 demo 里实际上只是辅助 DOM 操作和 ajax 加载数据词云图本身不依赖 jQuery。提示如果你的页面里已经有了别的 jQuery 版本可以先把jquery-1.9.1.min.js换成项目已有的版本词云渲染不会感知 jQuery 的存在。真正不能乱动的是主库和 wordcloud 插件的配对关系。2.2 为什么 jQuery 1.9.1 会出现在词云图的包里这个 demo 是早年典型的写法用 jQuery 的$.ajax拉取远程关键词数据再塞进 ECharts 的setOption。1.9.1 是 2013 年左右的版本在老项目里兼容性最稳$.ajax、$.each这些接口到今天也没怎么变。你完全可以用原生fetch替代fetch(data.json) .then(function (res) { return res.json(); }) .then(function (data) { myChart.setOption({ series: [{ type: wordCloud, data: data }] }); });这段代码的逻辑是先请求data.json拿到词频数组再调用setOption做增量更新词云图会自动重新布局不需要手动清空旧数据。参数说明.then链式处理异步结果第一层把响应流转成 JSON第二层拿到数组后直接注入图表增量更新是 ECharts 的默认行为只要data数组变了布局就会重排旧文字不会残留。2.3 echarts 3 与 echarts 5 混合使用的典型报错我见过最多的报错是Cannot read property getZr of undefined出现这个基本是主库 5.x 配合了为 3.x 编译的 wordcloud 插件。原因在于 ECharts 5 重构了扩展 API 的注册时机旧插件在init阶段拿不到完整的实例上下文。处理方式有两种全部降到 3.x 或 4.x用包内的echart3.js或去 CDN 拉echarts4.9.0全部升到 5.x去官方仓库拉取最新编译版的echarts-wordcloud.js不要混搭。!-- 方案一主库走 3.x与包内一致 -- script srcjs/echart3.js/script script srcjs/echarts-wordcloud.js/script !-- 方案二主库走 5.x需要配套的新版插件 -- script srchttps://cdn.bootcdn.net/ajax/libs/echarts/5.2.1/echarts.min.js/script script srcjs/echarts-wordcloud.js/script参数说明src的顺序不能颠倒主库必须先加载插件后加载否则插件注册系列类型时找不到echarts全局对象直接抛ReferenceError。方案二里如果echarts-wordcloud.js还是旧版编译产物依旧会报错所以先确认插件代码头部是否引用了echarts的模块系统接口。2.4 一个能直接打开的 index.html 骨架参考包内index.html的结构核心是这样一段div idwc stylewidth: 800px; height: 600px;/div script srcjs/echart3.js/script script srcjs/jquery-1.9.1.min.js/script script srcjs/echarts-wordcloud.js/script script var myChart echarts.init(document.getElementById(wc)); var data [ { name: Vue, value: 100 }, { name: React, value: 80 }, { name: Angular, value: 60 }, { name: Svelte, value: 30 } ]; myChart.setOption({ series: [{ type: wordCloud, shape: circle, sizeRange: [12, 60], rotationRange: [-90, 90], data: data }] }); /script这段代码里需要注意echarts.init的容器必须有明确宽高否则画布初始化为 0×0图表整个不显示data数组里用的是name和value字段这是echarts-wordcloud的标准数据结构有些老教程写weight或count在标准插件里不会被识别。sizeRange决定字号区间rotationRange决定旋转范围这两个参数是词云视觉表现的关键后面的章节会细说。3. 配置参数逐项拆解shape、sizeRange、旋转与颜色3.1 shape 参数内置形状与自定义形状函数shape是 series 级别的一个配置项用来限定整个词云布局的外轮廓。常见取值包括circle、rect、diamond、triangle、pentagon、star。源码实现上shape会传入布局算法每个单词在画布上放置时会根据当前形状计算可落点的范围而不是简单地把词排在一条直线上。自定义形状是更进阶的玩法传一个函数进去shape: function theta(theta) { var r 10; return [r * Math.cos(theta), r * Math.sin(theta)]; }参数说明theta是极坐标下的角度返回值是[x, y]坐标对插件会把角度转成一个几何边界词只能落在这个边界内。这个函数适合做品牌 LOGO 形状的词云比如把轮廓采点后形成极坐标方程。需要注意函数返回的坐标值相对中心点偏移尺寸过大时词可能落到画布外配合drawOutOfBound: false可以裁掉越界部分。3.2 sizeRange 决定视觉重心sizeRange: [12, 60]表示最小字号 12 像素、最大字号 60 像素。插件内部会对数据的value做线性映射权重最高的词拿到 60权重最低的拿到 12中间值按比例插值。如果你发现所有词一样大先确认是不是value字段传成了字符串比如value: 100内存里比较大小没问题但字号映射时会出偏差。提示sizeRange的最大值不建议超过容器短边的一半。800×600 的容器里最大字号 300会出现词互相重叠、布局算法反复碰撞直到性能下降最终显示效果还不如 60。字号映射是纯线性还是对数插件没有给开关。数据方差特别大时比如一个词权重 100000其余全是个位数线性映射会把小词全部压到最小字号视觉上只剩一个词。常见做法是对value取对数或开根号后再入库var maxVal Math.max.apply(null, rawData.map(function (d) { return d.value; })); var data rawData.map(function (d) { return { name: d.name, value: Math.sqrt(d.value / maxVal) * 200 }; });逻辑说明先算出原始权重最大值每个值除以最大值后开根号再乘 200 放大这样大权重和小权重之间的差距被压缩词云的高频词仍然突出但小词不会小到看不见。参数说明Math.sqrt是核心它把 0-1 区间的比值做非线性放大乘 200 只是给后续的sizeRange映射留足数值区间具体数值取决于你想要的灵敏度。3.3 rotationRange 与 rotationStep旋转策略rotationRange: [-90, 90]允许词在负 90 度到正 90 度之间旋转rotationStep: 45表示每次旋转的步长是 45 度也就是一个词可能的角度只有 -90、-45、0、45、90 这几个离散值。步长越小角度选择越多视觉效果越活泼但布局计算量也越大。不少教程里提到的textRotation、rotation这类写法在标准echarts-wordcloud插件里并不存在属于自定义版本或误写。如果你的页面里配了textRotation: [0, 90, -90]但完全没生效不用奇怪把它换成rotationRange加rotationStep就好。rotationRange: [-90, 90], rotationStep: 45,参数说明rotationRange只定义允许的旋转角度区间rotationStep定义步长两者配合使用。注意rotationStep必须能被rotationRange的区间长度整除比如 180 除以 45 是 4刚好整数。如果你写rotationStep: 30180 除以 30 也是整数角度集合变成 -90、-60、-30、0、30、60、90也是可以的。想全部横排把rotationRange设为[0, 0]即可。3.4 textStyle 的 color 支持函数与随机色词云图的文字颜色有两个入口。一个是全局textStyle作用于所有词一个是data[i].textStyle单独控制某一个词的颜色。标准插件里color支持字符串、对象和函数常见的动态配色方案textStyle: { color: function () { return rgb( [ Math.round(Math.random() * 160 60), Math.round(Math.random() * 160 60), Math.round(Math.random() * 160 60) ].join(,) ); } }逻辑说明每次给一个词上色时函数被调用一次随机产生 RGB 三个通道在 60 到 220 之间的值。下限 60 是为了避免太暗的颜色在白色背景上看不清上限 220 是为了避免纯白和背景混在一起。参数说明如果想让颜色有主题倾向比如都偏蓝可以固定 B 通道为 200只随机 R 和 G如果按权重渐变可以在函数里读到当前的params.name或params.value再返回对应颜色。3.5 一张速查表收拢全部常用参数参数类型默认值作用注意点typestring无固定wordCloud缺了插件直接空白不报错shapestring/functioncircle词云外轮廓形状函数模式返回极坐标点sizeRangearray[12, 60]字号最小最大值最大值别超容器短边一半rotationRangearray[-90, 90]允许旋转的角度区间单位是度不是弧度rotationStepnumber45旋转步长需能被区间长度整除gridSizenumber8布局网格像素单位值越小密度越高越卡drawOutOfBoundbooleanfalse是否绘制越界文字设为 true 会看到词延伸到容器外shrinkToFitbooleanfalse超出边界时是否缩小字号大数据量下建议开启textStyle.colorstring/function#333文字颜色函数模式每次调用返回一个色值dataarray无{ name, value }数组value 必须是数字类型gridSize是很多人忽略的参数。它控制词云布局时使用的网格粒度网格越小词之间缝隙越小布局越紧凑但碰撞检测的计算量按平方增长。1000 个词时gridSize: 4可能直接卡掉浏览器标签页改成 8 或 12 会明显流畅代价是词与词之间的空隙变大视觉上稍微松散一些。4. 数据预处理与动态更新从原始文本到词频数组4.1 中文文本的切词与停用词过滤词云图本身不负责分词它接收的是已经统计好的{ name, value }数组。如果你手头的原始数据是一段新闻文本或评论字符串需要先做分词。英文按空格和标点切分即可中文没有天然分隔符常见做法是引入分词库或者在前端用一个简单的最小切分策略。var text 前端开发者的竞争力在于工程效率和综合能力; var words text.match(/[\u4e00-\u9fa5]{2,4}/g) || []; var stopWords [在于, 可以, 一个, 我们]; var freq {}; words.forEach(function (w) { if (stopWords.indexOf(w) -1) return; freq[w] (freq[w] || 0) 1; }); var data Object.keys(freq).map(function (name) { return { name: name, value: freq[name] }; });逻辑说明正则[\u4e00-\u9fa5]{2,4}从文本里抽取连续 2 到 4 个汉字的片段这种切分方式精度一般但不需要额外库。停用词表stopWords里装的都是没有实际意义的高频词命中后直接跳过。最终遍历freq对象把每个词的计数转成{ name, value }结构。参数说明正则里的 2 到 4 是把相邻汉字按滑窗切出候选词实际项目中你会把这一步换成精确分词接口但数据流向是一致的无论分词怎么做最终都要产出name和value两个字段的数组。4.2 权重归一化与离群值处理统计完的词频直接进sizeRange是可以的但数据里如果出现一个爆炸性关键词比如某个词出现 10000 次别的词只有 1 到 5 次线性映射会让后者的字号全部压到最小视觉上变成只有一个大词加一堆小蚂蚁。处理方式在第 3 章提过开根号更稳妥的是先做分位数裁剪再开根号var values data.map(function (d) { return d.value; }); values.sort(function (a, b) { return a - b; }); var p90 values[Math.floor(values.length * 0.9)]; data.forEach(function (d) { d.value Math.min(d.value, p90); d.value Math.pow(d.value / p90, 0.7) * 100; });逻辑说明先取所有权重的 90 分位值p90把超过它的值全部截断这相当于去掉长尾里的极值。第二步做归一化每个值除以p90后取 0.7 次幂最后乘 100。0.7 次幂介于开根号0.5和线性1.0之间是一种可调的压缩强度数字越小压缩越狠。参数说明p90的具体位置可以根据数据分布改成p95核心目的是让最高权重与中位权重之间的差距不超过一个数量级否则字号映射必然失衡。4.3 异步加载后端数据后 setOption 刷新真实项目里词云的数据通常来自后端接口可能是热门搜索词、标签统计数据、日志聚合结果。拿到数据后不要重新init直接用setOption做增量更新这样 ECharts 会复用之前的画布和布局状态减少一次全量重建var myChart echarts.init(document.getElementById(wc)); function loadWordCloud() { fetch(/api/hot-words) .then(function (res) { return res.json(); }) .then(function (json) { var data json.data.map(function (item) { return { name: item.word, value: item.count }; }); myChart.setOption({ series: [{ type: wordCloud, data: data }] }); }) .catch(function () { console.log(加载失败本次不上报); }); } setInterval(loadWordCloud, 60000);逻辑说明loadWordCloud把请求封装成函数每次调用都会重新拉取接口并覆盖data。60 秒一次做定时刷新适合舆情大屏或运营看板场景。参数说明setOption里只传了data之前设置过的shape、sizeRange会保留这是 ECharts 的增量合并机制如果你希望改成完全新的配置传notMerge true作为第二个参数即myChart.setOption(config, true)会把旧配置清掉重新来。提示刷新频率超过每 10 秒一次时建议在setOption前调用myChart.clear()避免布局状态叠加导致的内存持续上涨。低频刷新不需要。5. 把 demo 收进生产环境事件绑定、性能与排查5.1 click 事件拿不到关键词看 data 的对象结构给词云加点击跳转是高频需求但经常出现params.name是undefined的情况。原因是事件参数里的data字段需要与 series 里定义的字段一致。标准echarts-wordcloud插件里data的结构如果是{ name: Vue, value: 100 }那么在事件回调里拿到的就是params.name、params.value。但如果你的数据源用的是{ word: Vue, count: 100 }事件回调里params.name自然拿不到。myChart.on(click, function (params) { if (params.componentType series params.seriesType wordCloud) { window.open(https://example.com/search?q encodeURIComponent(params.name)); } });逻辑说明on方法注册点击监听回调里先判断componentType是不是series再判断seriesType是不是wordCloud避免误触发其他系列组件。参数说明encodeURIComponent对关键词做 URL 编码中文词不带编码直接拼进地址会产生乱码。5.2 大数据量与重绘性能词云布局是 CPU 密集型计算核心瓶颈在碰撞检测。100 个词毫无压力1000 个词开始有感知5000 个词以上页面基本卡死。如果你需要展示的词超过 2000 个我一般会先做 top-N 截断var topN data.sort(function (a, b) { return b.value - a.value; }).slice(0, 500);参数说明sort按value降序排slice(0, 500)只保留前 500 个词。词云图的价值在于快速呈现主要特征而不是显示全量低频词截断掉长尾对信息损失非常小但性能提升是数量级的。配合gridSize: 10和shrinkToFit: true500 个词在任何主流设备上都能顺畅渲染。另外不要把setOption放在window.resize事件里直接触发。常见做法是节流var resizeTimer; window.addEventListener(resize, function () { clearTimeout(resizeTimer); resizeTimer setTimeout(function () { myChart.resize(); }, 200); });逻辑说明resize事件在拖拽窗口时高频触发每次都调用myChart.resize()会诱发重绘。这里用clearTimeout加setTimeout做了 200 毫秒的防抖拖拽停下来 200 毫秒后才真正执行一次调整。参数说明200 毫秒是常规选择如果图表较重可以调到 300 到 500 毫秒setTimeout的返回值每次都覆盖resizeTimer就是为了取消上一次未执行的定时任务。5.3 常见报错排查表现象可能原因对应解法页面空白控制台无报错容器高度为 0给div设置明确的px宽高Cannot read property getZr of undefined主库与 wordcloud 插件版本不匹配统一降到 3.x或升级新插件词全部横排没有旋转rotationRange写成[0, 0]改成[-90, 90]加rotationStep: 45所有词字号一样大data里value是字符串用Number()转成数字词被截断到容器外drawOutOfBound为false且布局空间不足调大gridSize或减少词量一个超大词压制全场数据方差过大90 分位裁剪后开根号归一化中文显示为方块字体栈缺少中文字体textStyle.fontFamily设置Microsoft YaHei或sans-seriftextStyle.fontFamily是最低调但最常见的坑。ECharts 默认字体栈在部分 Linux 服务器上不包含中文字形词云里所有中文渲染成方块。直接在textStyle里指定fontFamily: Microsoft YaHei, PingFang SC, sans-serif服务端渲染或导出图片时也要保证系统安装了对应字体否则导出图里中文依然是方块。这个参数建议在项目初始配置时就写好不要等上线后再补。本文还有配套的精品资源点击获取
返回列表