图表数据刷新需视觉过渡而非单纯提速;Canvas柱状图用requestAnimationFrame逐帧更新currentHeight,按0.12缓动系数逼近targetHeight,避免跳变。

图表数据刷新时加过渡效果,核心不是“重绘得快”,而是让视觉变化有节奏、可预期。直接改值或全量重画,用户会感觉卡顿或突兀。
Canvas 柱状图用 requestAnimationFrame 渐变高度
Canvas 本身不支持 CSS transition,必须手动控制帧动画。关键在于不让柱高“跳变”,而是每帧逼近目标值。
- 为每个柱子维护一个
currentHeight变量,初始为 0,目标是归一化后的targetHeight - 在
requestAnimationFrame回调中更新:currentHeight += (targetHeight - currentHeight) * 0.12(系数 0.12 提供自然缓动) - 当
Math.abs(targetHeight - currentHeight) 时,可停止该柱子的更新,避免无限小数抖动 - 别在每次动画帧里
clearRect(0, 0, canvas.width, canvas.height)——只清空局部区域更省资源,例如ctx.clearRect(x - 5, 0, barWidth + 10, canvas.height)
SVG 图表用 CSS transition 控制 transform 和 opacity
SVG 元素(如 <rect>、<circle>)支持 CSS transition,但仅限于部分属性。直接改 y 或 height 会触发重排,应绕开。
- 把柱子高度映射到
transform: scaleY(),基础态设transform: scaleY(0),更新后设transform: scaleY(0.78)(需配合transform-origin: bottom) - 同时过渡
opacity,避免新旧柱子叠加时出现视觉冲突 -
transition必须写在<rect>的默认样式里,不能只写在 class 切换后的规则中,否则移出无动画 - 避免
transition: all——它会偷偷监听fill、stroke-width等非预期变化,拖慢渲染
HTML + Chart.js 等库启用内置过渡
Chart.js v4+ 默认开启动画,但常被误关或配置不当。手动刷新数据后,过渡不生效,多因状态未正确标记。
立即学习“前端免费学习笔记(深入)”;
- 确保配置中启用了动画:
options.animation = { duration: 300 },且未被options.plugins.legend.display = false等副作用干扰 - 调用
chart.data.labels = newLabels后,必须跟chart.data.datasets[0].data = newData,再执行chart.update('active')(传'active'触发活跃过渡) - 若用 Vue/React 封装 Chart.js,注意 ref 绑定是否延迟——DOM 节点未挂载完就调
update(),动画会静默失败 - 不要在
chart.update()前改style.display或visibility,这会让浏览器跳过动画快照
动态插入新数据行时强制触发 transition 起点
表格类图表(如带滚动的指标看板)插入新行后,fade-in 类常一闪而过。这是因为浏览器把 DOM 插入和样式变更合并为一次渲染,没机会记录初始态。
- 插入后立即读取布局信息,强制重排:
void newRow.offsetHeight(这句必须在加动画 class 之前) - 再添加类,例如:
newRow.classList.add('chart-row-enter')→ 浏览器此时才开始记录opacity: 0 → 1的起点 - 如果父容器用了
display: flex模拟表格,iOS Safari 下建议加will-change: transform,否则transform动画可能降级为软件渲染 - 避免对
tr直接设height过渡——它会触发重排;改用transform: scaleY(0)+origin: top更稳
最易被忽略的一点:所有过渡都依赖“两个明确状态”。无论是 Canvas 的数值逼近、SVG 的 transform 变化,还是 Chart.js 的 update 调用,只要起始值或目标值是 NaN、undefined 或未参与布局(比如 display: none 中的元素),过渡就会失效——不是代码错了,是浏览器根本没拍到第一张“照片”。



















