☰
Echarts折线图渲染优化方案
2026/10/10 6:18:49 网站建设 项目流程

Echarts折线图渲染优化方案

本章节介绍基于echarts折线图的渲染优化

文章目录

  • 系列文章目录
  • 前言
  • 一、前端优化方案
    • 1.Echarts配置
    • 1.1 sampling的配置
    • 1.2 dataZoom 配置
    • 1.3 progressive分批渲染
    • 1.4 关闭动画(不抽点,但会减少重绘和交互开销配置项)
    • 2.数据处理
  • 二、与后端协同优化方案

前言

根据业务需要,后端一次性返回前端所有数据,在X坐标轴展示时间,Y轴坐标展示对应的值;
后端取24小时的数据,前端按照秒级单位来描点连线;24 小时按秒连线大约是 86400 个点。图宽只有大约 1000 像素,每一列像素上会叠几十个点,高低值连在一起就会糊成一块面,这是点数和像素不匹配,导致UI展示不友好,页面鼠标悬浮等动作会延迟卡顿;
技术栈:vue2.6.10版本, echrts5.4.0版本

一、前端优化方案

1. 配置首次渲染稀疏点,让折线图基本走势正常展示;

2. 配置缩放dataZoom,允许当窗口拉大后展示更多的点;

3.处理x轴的坐标,把字符串类型的时间改为date类型;

1.Eharts配置

1.1开启 LTTB 降采样

sampling: 'lttb'会智能保留曲线的“形状特征”(如峰值、谷值、拐点),过滤掉大量冗余的直线段点, 视觉上趋势不变,性能大幅提升;同时记得加上symbol: 'none',避免为每个数据点绘制标记,这也能省下不少渲染开销;

1.2 dataZoom配置

不要让图表一开始就渲染全部时间范围。结合dataZoom设定初始只展示一个较窄的时间窗口;

dataZoom: [ { type: 'inside', start: 0, end: 10 }, { type: 'inside', start: 0, end: 10 } ],

1.3 progressive分批渲染

可以让渲染过程更平滑

  • progressiveThreshold: 3000:点数达到这个值才分帧
  • progressive: 400:每一帧画多少个点
  • progressiveChunkMode:柱状默认'mod'

生效条件:这条 series 的视图实现了incrementalPrepareRender,并且progressive为真、点数不少于阈值。每一帧画progressive个点,画完再画下一帧,避免一次布局卡死主线程;

1.4 不抽样展示,但会减少重绘和交互开销

  • animationThreshold: 2000(根配置)。单条 series 点数超过它,动画自动关掉。
  • hoverLayerThreshold: 3000(根配置,真正被读取的是这一项)。图形数量超过它,高亮改到单独的 hover 层,避免整图重画。
  • echarts.init(dom, null, { useDirtyRect: true })。只重画变化区域。默认关闭。拖动 dataZoom、十字准星时收益大;整图setOption替换 series 时收益小。
  • setOption(option, { lazyUpdate: true })。把本次更新推迟到下一帧,连续触发时合并成一次渲染。
  • silent: true。这条 series 不响应鼠标,省掉命中检测。
  • showSymbol: false、showAllSymbol。不创建每个点的 symbol。8 万个圆点比折线本身更贵。
  • clip: true。画出坐标范围的部分裁掉,少画可视区域外的路径。
  • blendMode。默认source-over。改成别的混合模式会关掉一些 canvas 加速。
  • dataZoom 的throttle。拖动时限制datazoom事件频率,默认约 100ms 量级。realtime: false则松手后才更新图表。

注意:large:true的配置用于散点图、柱状图、路径线图(lines)上,折线视图不生效

2.数据处理

// 删除 xAxisData 相关代码

const start = Date.parse(result.errorTimeS); // 起始时间戳

result?.signals?.forEach((item) => {

const key = this.switchSignalType(item.signalCode, item.signalType);

// 把纯数值数组 改为 [[timestamp, value], ...] 二维数组

seriesData[key] = item.values.map((v, i) => [start + i * 1000, v]);

});

// 调用时不再传 xAxisData

this.initChart(index, seriesData);

原数据格式为字符串数组:[v1, v2, v3, ...]
改后时间戳的二维数组:[[ts1,v1], [ts2,v2], [ts3,v3], ...]

echarts会根据像素密度匹配格式,原来类目配置为:

xAxis: {

type: "category", // category axis, each data point is an independent category

boundaryGap: false,

data: xAxisData, // passes in the pre-formatted time string array

axisLabel: {

formatter: function (value) {

return value.substring(11, 19); // manually extract HH:mm:ss

},

},

}

把type改为:“time”, 优势对比如下:

操作改前改后
moment().format()调用次数~80,000 次0 次
xAxis.data 数组80,000 个字符串无(省内存)
刻度格式化手动 substringECharts 内部按需计算(只格式化屏幕可见的十几个标签)
dataZoom 缩放时的刻度更新需重新计算自动处理

二、与后端协同优化方案

  1. 初始加载:前端请求“最近 1 小时”数据,后端按秒级返回(假设 3600 个点)。

  2. 前端渲染:ECharts 开启sampling: 'lttb',symbol: 'none',animation: false,progressive: 2000。将绘制点数可能被降到 1000 左右,流畅。

  3. 用户缩放:用户将 DataZoom 拖拽到“最近 24 小时”。

  4. 增量请求:前端监听到dataZoom事件,根据新的时间范围向后端请求这 24 小时的数据。后端此时可以按分钟聚合返回(约 1440 个点),而不是秒级。

  5. 更新图表:前端用新数据setOption,由于数据量依然可控,且已经关闭了动画,更新过程不会卡顿。

与后端协同方案实现思路:让折现趋势展示完整,当请求为24h的数据时,前端渲染的为小时或分钟级别的描点,只有缩放到了近20分钟内按秒级展示;

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询