局部重绘是只处理真正变化的区域而非全图重画。核心是精准计算并合并脏区矩形,仅清除和绘制该区域;结合离屏缓存、分层管理与变更比对,跳过无效更新,显著提升性能。

局部重绘不是“画得更细”,而是“只动该动的那块”。核心思路是:不全屏清空、不全图重画,只处理真正发生变化的区域。
明确脏区,精准标记变化范围
脏区(Dirty Region)是你必须重绘的最小矩形。它不是凭感觉估的,而是靠计算得出的:
- 每当一个图形的位置、尺寸、颜色或文本内容更新时,立刻算出它新旧状态的包围盒
- 例如一个圆从 (100,80) 移到 (130,95),半径 12 → 脏区左上为 (88,68),右下为 (142,107),宽高分别为 54 和 39
- 多个变化区域要合并:取所有 x 的最小值、y 的最小值,再算出最大 x+w 和最大 y+h
- 用
Math.floor()对齐像素坐标,避免亚像素清除导致模糊或抖动 - 维护一个全局对象如
dirtyRect = {x, y, width, height},初始为null;每次调用markDirty(x, y, w, h)合并更新
只清空、只绘制脏区
全量 clearRect(0, 0, canvas.width, canvas.height) 是性能杀手,尤其在高分屏或高频动画中:
- 清屏前只执行
ctx.clearRect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height) - 若脏区内含阴影、半透明叠加或
globalAlpha变化,单纯清除可能破坏混合效果 → 此时应改用离屏缓存+合成方案 - 若脏区完全超出可视范围(如
x + w ≤ 0或y ≥ canvas.height),直接跳过本次重绘
结合分层与离屏缓存提升效率
把“不变”和“常变”分开管理:
- 创建离屏 canvas(
offscreenCanvas),一次性绘制背景网格、底图、UI 边框等静态内容 - 主 canvas 只负责动态元素(如拖拽节点、实时连线、输入文字)
- 局部刷新时:先用
ctx.drawImage(offscreenCanvas, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height)把静态部分“盖回去”,再在其上绘制最新动态内容 - 对文本、路径等对象缓存上一帧快照(如
JSON.stringify({text, font, x, y})),仅当比对不同时才标记脏区
跳过无效更新,减少冗余操作
很多卡顿来自“本不该画却画了”:
- 动画中位移增量小于 0.5px 且无缩放/旋转变化时,可忽略本次更新
- 使用
ctx.save()/ctx.restore()包裹局部样式变更虽安全,但开销不小;更推荐批量同样式绘制,减少 save/restore 调用 - 在 LiteGraph.js 等框架中,可直接调用
setDirtyArea(x, y, width, height)触发局部重绘,无需手动管理脏区逻辑
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











