裁剪框前端显示位置需按原图坐标换算,导出参数必须对应原始像素;缩放比应在图片加载后立即计算并缓存;拖拽缩放须用 pointer 事件并调用 setPointerCapture;8 锚点支持自由调整并限制最小尺寸与边界;导出前须校验并归一化裁剪区域。

裁剪框必须基于原图坐标计算
前端显示的裁剪框位置和尺寸,只是视觉参考。真正导出时用的 x、y、width、height 四个值,必须对应原始图片的像素坐标。比如用户在 400×300 的 canvas 上拖出一个 100×100 的框,而原始图是 4000×3000,那实际裁剪起点不是 (100, 100),而是 (1000, 1000),宽高也得放大 10 倍。缩放比例 = 原图宽 / canvas 显示宽(或等比取 height 方向),这个值必须在图片加载完成后立刻算出并缓存。
拖拽与缩放需统一用 pointer 事件
只监听 mousedown/mousemove 会丢掉移动端操作,resize 后坐标还会错乱。正确做法是:
- pointerdown 时记录起始点 clientX/clientY,并调用 setPointerCapture() 锁定事件流
- pointermove 中根据偏移量更新裁剪框 left/top/width/height,同时实时换算成原图坐标
- 监听 window.resize,在容器尺寸变化后重新计算缩放比和当前 background-position(若用背景图方案)或 canvas 绘制比例(若用 canvas 方案)
8 个控制点实现自由调整
标准矩形裁剪框应提供 8 个可拖拽锚点:四角 + 四边中点。每个点有唯一标识(如 'nw'、'n'、'ne'…),点击时判断距离是否小于阈值(PC 端建议 6px,移动端 12px)。拖动时按方向约束行为:
- 拖动角点(如 'nw'):同时修改 x、y、width、height
- 拖动边点(如 'n'):只改 y 和 height,width 保持不变
- 所有调整都需限制边界——不能让 width 或 height 小于 20px,也不能让裁剪框超出图片可视区域
导出前务必校验裁剪区域合法性
用户可能拖出无效区域:比如 x 为负数、width 超过原图宽度、或裁剪框完全落在图片之外。导出前要强制归一化:
- x = Math.max(0, Math.min(x, naturalWidth - width))
- y = Math.max(0, Math.min(y, naturalHeight - height))
- width = Math.max(20, Math.min(width, naturalWidth - x))
- height = Math.max(20, Math.min(height, naturalHeight - y))
归一化后再传给 ctx.drawImage(img, x, y, width, height, 0, 0, outputWidth, outputHeight)。

















