说实话,刚开始用 ECharts 的时候,我也以为这玩意儿就是“复制粘贴文档代码”那么简单。直到我第一次在线上报表里把一堆散点图强行堆叠成折线图,结果发现线条乱飞、数据对不上,那一刻真的想顺着网线去拍文档作者的肩膀问问原理。今天这篇不聊那些官方的套话,咱们直接钻进坑里,看看那些让人头秃的真实报错和背后的逻辑。
别再把散点当成折线的点了
很多新手有一个误区:在 series 里同时放两个类型,一个 scatter 一个 line,期待它们自动对齐。结果往往是这样:散点飘在半空,折线却从原点出发,或者两条线完全错位。
我第一次遇到这个坑时,控制台没报错,但图表看起来就像被揍了一顿。代码大概长这样:
option = {
xAxis: { type: 'category' },
yAxis: {},
series: [
{ type: 'scatter', data: [[1,20], [2,30], [3,25]] },
{ type: 'line', data: [20, 30, 25] }
]
};
乍一看没问题吧?数据都一样,为啥 X 轴对不上?
真实报错案例:我当时看到 Y 轴数值完全对不上,以为是数据问题,查了半小时代码。后来才发现,scatter 的 data 是二维数组([x, y]),而 line 的 data 是一维数组(y),且 X 轴没有数据。ECharts 会默默地把折线图的 X 轴当成索引 0,1,2… 但你的分类轴是 ‘1’,‘2’,‘3’,根本对不上。
正确做法:
option = {
xAxis: { type: 'category', data: ['1', '2', '3'] },
yAxis: {},
series: [
{ type: 'scatter', data: [['1',20], ['2',30], ['3',25]] },
{ type: 'line', data: [20, 30, 25] }
]
};
关键在于:scatter 和 line 共享同一个 X 轴数据,且 scatter 的 data 必须是 [x, y] 的二维数组。如果你只想让散点作为折线的“标记”,其实只需要一个 series 就够了:
series: [{
type: 'line',
data: [20, 30, 25],
symbol: 'circle', // 每个点都是圆
symbolSize: 10,
lineStyle: { width: 2 }
}]
动态折线图的“心跳”陷阱
动态折线图听起来很炫,但实现起来坑不少。最常见的场景是:每隔 1 秒推入新数据,旧数据剔除,形成滚动效果。
我第一次做这个的时候,数据确实动起来了,但图表突然“闪”了一下,然后卡死。控制台报了一个我从未见过的错:
TypeError: Cannot read property 'length' of undefined
代码长这样:
setInterval(() => {
newData.push(Math.random() * 100);
if (newData.length > 50) newData.shift();
chart.setOption({
series: [{ data: newData }]
});
}, 1000);
问题在哪? setOption 的时候,如果只传 series,ECharts 会尝试合并配置,但有时会因为内部状态不一致导致崩溃。更隐蔽的问题是:你没有指定 xAxis.data,而动态数据又在不断变化,X 轴的数据可能变成 undefined。
避坑指南:
- 显式声明 X 轴数据,即使它是时间轴或类别轴。
- 使用
replaceOption参数(ECharts 5+)或手动管理配置。 - 避免在动态更新时频繁创建新数组,尽量复用或浅拷贝。
正确写法:
let data = [];
let timestamps = [];
setInterval(() => {
const now = new Date().toLocaleTimeString();
const value = Math.random() * 100;
timestamps.push(now);
data.push(value);
// 保持最多 50 个点
if (data.length > 50) {
timestamps.shift();
data.shift();
}
chart.setOption({
xAxis: { data: timestamps },
series: [{ data: data }]
}, true); // 第二个参数是 notMerge,强制全量更新,避免合并错误
}, 1000);
注意最后的 true 参数,这是 setOption 的 notMerge 选项。在某些复杂动态场景下,强制全量更新反而比合并更稳定。
堆叠图的“消失”之谜
堆叠柱状图或面积图是 ECharts 的强项,但一旦数据里有 0 或 null,就会出鬼。
我曾经做过一个能耗监控大屏,柱状图是堆叠的(空调、照明、设备)。某天凌晨,所有读数归零,结果图表里那些柱子“凭空消失”了,只剩下一片空白。更诡异的是,当数据恢复时,堆叠顺序乱了——空调和照明叠反了。
真实报错:控制台没报错,但视觉上一个明显的 bug。
原因分析:
0值在堆叠中会被忽略,如果所有 series 都是 0,整个堆叠区域就没了。null值会断开折线,但在堆叠图中,null会导致后续数据错位。- 堆叠顺序依赖于 series 的定义顺序,如果动态加载 series 时顺序变了,堆叠就乱了。
解决方案:
// 确保数据中 0 值不被视为缺失
series: [
{ name: '空调', type: 'bar', stack: 'total', data: [0, 10, 20] },
{ name: '照明', type: 'bar', stack: 'total', data: [0, 5, 15] },
{ name: '设备', type: 'bar', stack: 'total', data: [0, 8, 12] }
]
// 如果数据可能是 null,预处理成 0
data = data.map(v => v === null ? 0 : v);
另外,固定 series 的顺序,不要动态增减 series 定义,只更新 data。
坐标系错位的“阴阳怪气”
有时候,你的数据明明是对的,但图表就是显示不对。比如 Y 轴最大值 100,你的数据是 50,但点画在了顶部。
我第一次遇到这个,以为是坐标轴反转了,结果查了半天发现是 yAxis.inverse: true 被某个默认配置悄悄设上了。
常见场景:
- 使用了
grid组件但没设对left/right/top/bottom,导致坐标系偏移。 xAxis和yAxis的type设错了,比如数值轴用了category。- 多个直角坐标系重叠,后绘制的覆盖了前面的。
调试技巧:打开浏览器控制台,输入 chart.getModel().getSeries()[0].getData(),看看实际渲染的数据是不是你传入的。如果数据本身没错,那就是坐标系的问题。
// 强制指定坐标系位置,避免重叠
grid: {
left: '10%',
right: '10%',
top: '15%',
bottom: '15%'
}
性能瓶颈:当数据量超过 10 万条
动态折线图在处理海量数据时,帧率会暴跌。我第一次在线上监控页面放 10 万条历史数据,浏览器直接卡成 PPT。
原因:ECharts 默认会对所有数据进行渲染,包括 SVG 路径计算、文本绘制等。
优化方案:
- 启用
large模式:
series: [{
type: 'line',
data: largeData,
large: true,
largeThreshold: 2000 // 超过 2000 个点启用 large 模式
}]
- 使用
sampling: 'lttb':自适应降采样,保留数据特征的同时减少点数。
series: [{
type: 'line',
data: largeData,
sampling: 'lttb',
lineStyle: { width: 1 }
}]
- 数据分片加载:不要一次性推 10 万条,按 1000 条一组加载。
真实报错合集(来自血泪史)
报错 1:Cannot read property 'get' of null
- 场景:动态移除 series 后,tooltip 还在引用已删除的 series。
- 解决:移除 series 时,同时清空 tooltip 的
formatter或重新初始化图表。
报错 2:Data array is not defined
- 场景:
setOption时传了空对象{}。 - 解决:确保每次
setOption至少传了series或必要的配置。
报错 3:Y 轴刻度无限循环
- 场景:数据全是 0 或极小值,ECharts 自动计算刻度时出错。
- 解决:手动指定
yAxis.min和yAxis.max,或者对数据进行平移。
给小朋友也能讲清楚的比喻
想象你在搭积木:
- 散点图是散落在桌上的积木块,每块都有自己的位置。
- 折线图是用绳子把这些积木块按顺序串起来,形成一条线。
- 堆叠图是把不同颜色的积木块摞在一起,看看总共多高。
- 动态折线图是机器人一边往桌上放积木,一边用相机实时拍照,照片自动连成线。
如果你把绳子串错了顺序(坐标系错位),或者积木块没放稳(数据为 null),照片就会糊掉(图表显示错误)。
最后的心态建议
ECharts 的文档其实写得不错,但很多细节藏在“注意事项”里。遇到坑时:
- 先看控制台报错,哪怕只是 warning。
- 最小化复现:把代码精简到只剩核心部分,排除干扰。
- 查 GitHub Issues:很多坑前人已经踩过,搜索
echarts github issues+ 报错关键词。 - 别怕看源码:ECharts 是开源的,看看它怎么解析你的数据,比自己瞎猜快得多。
图表是给人看的,代码是给机器跑的。让机器跑得顺畅,才能让人看得明白。希望这些坑你能绕着走,或者至少,走的时候知道脚下是什么。
