Canvas动态调色板核心是像素级取色与容差泛洪替换:点击获取坐标并换算为画布像素位置,读取ImageData中对应RGBA值;以该色为种子,用栈实现Flood Fill扩散替换相似色区域,欧氏距离判定容差,保持Alpha不变;所有操作在内存Uint8ClampedArray中批量完成,mouseup后一次性putImageData更新,支持历史色缓存与一键还原。

用 Canvas 实现动态调色板功能,核心不是“选颜色”,而是把用户点击/拖拽区域的像素颜色实时提取出来,并支持反向操作——把选定颜色批量替换到图像中指定区域。整个过程依赖像素级读写、坐标映射和颜色相似度判断,不依赖外部库。
获取点击位置的真实像素颜色
Canvas 本身不提供“取色器”API,需手动从 ImageData 中查坐标对应值:
- 监听 canvas 的 click 或 mousemove 事件,用
e.offsetX / e.offsetY获取视口坐标 - 调用
canvas.getBoundingClientRect()换算成画布内像素坐标:x = (e.offsetX - rect.left) * (canvas.width / rect.width) - 确保图像已完整绘制,再执行
ctx.getImageData(0, 0, canvas.width, canvas.height) - 按公式
index = (Math.floor(y) * width + Math.floor(x)) * 4定位 RGBA 四字节起始位置,取出data[index](R)、data[index+1](G)、data[index+2](B)
实现颜色替换(类似油漆桶或背景换色)
替换不是简单遍历全部像素,而是以点击点为种子,扩散填充颜色相近区域:
- 先读取点击点原始颜色
targetColor = [r, g, b],设定容差值(如 30) - 使用泛洪填充(Flood Fill)算法:用栈或队列存储待处理坐标,避免递归过深
- 对每个坐标 (x, y),计算当前像素与 targetColor 的欧氏距离:
dist = Math.sqrt((r1-r2)² + (g1-g2)² + (b1-b2)²),小于容差才替换 - 替换时只改 R/G/B,保持 A 不变;目标色由调色板实时提供,可随时切换
- 边界检查必须严格:x ∈ [0, width), y ∈ [0, height)
支持实时预览与批量更新
频繁调用 putImageData 会导致卡顿,尤其在大图或移动端:
立即学习“前端免费学习笔记(深入)”;
- 所有颜色替换操作都在内存中完成,用一个新
Uint8ClampedArray存储结果,不修改原 data - 仅在用户松开鼠标(
mouseup)或确认操作后,一次性putImageData写回 - 若需实时预览(如拖拽换色),限制重绘区域:只处理上一帧与当前帧的并集矩形,而非整图
- 可加一层半透明 canvas 叠在原图上,仅绘制替换区域的色块,减少计算量
调色板交互与颜色管理
调色板本身是 UI 控件,但要与像素操作联动:
- 用
<input type="color">或自定义色盘获取目标色,转为 RGB 数组:hexToRgb('#ff5733') - 记录“源色”和“目标色”,允许一键还原(把目标色区域恢复为源色)
- 历史颜色可存入数组,点击小色块即设为当前目标色,支持最多 10 个常用色缓存
- 替换完成后,自动将原点击色加入历史,形成闭环工作流



















