Canvas手写签名体验关键在压力敏感模拟与平滑算法:无压感时依速度拟合线宽,用二次贝塞尔曲线替代直线连接,并需高清适配、坐标归一化及防抖过滤。

Canvas 实现手写签名,真正影响体验的不是“能画出来”,而是“像不像真笔写的”——这取决于压力敏感模拟和平滑算法两个核心环节。没有压感硬件支持时,得靠速度、位移、时间差来拟合轻重;而平滑不是简单连点,是用数学曲线让转向自然、不断笔、不锯齿。
压力敏感:没有压感硬件,也能模拟“轻重缓急”
多数触摸屏不提供原生压力值,但用户书写天然有节奏:慢写粗、快写细,提按间有顿挫。可基于采样点的时间间隔与位移距离动态估算“等效压力”:
- 计算相邻点间移动速度:speed = √[(dx)² + (dy)²] / dt(dt 单位为毫秒)
- 设定合理阈值(如 0.5 px/ms 为中速),低于则线宽增大(模拟下压),高于则收窄(模拟提笔)
- 加入最小/最大线宽限制(如 1–6px),避免极端抖动导致线条过细或糊成块
- 起笔和收笔处额外加权:前3个点略增宽度,最后2个点渐细,模拟真实笔触的“入纸”与“出锋”
平滑算法:用二次贝塞尔曲线替代直线连接
直接 lineTo 会生成折线,尤其在快速转弯时明显生硬。正确做法是以三点一组构造二阶贝塞尔路径:
- 维护最近三个点:prev(上上点)、last(上一点)、current(当前点)
- 控制点取 last 与 current 的中点:cpX = (last.x + current.x) / 2
- 从 prev 出发,调用 quadraticCurveTo(cpX, cpY, current.x, current.y)
- 每新增一点就更新三元组,保证整条轨迹由连续、相切的曲线段拼接而成
高清适配与坐标归一化:避免“模糊”和“偏移”
签名看起来糊、位置飘、缩放后错位,90% 是 DPI 和坐标没对齐:
- 获取设备像素比 dpr = window.devicePixelRatio || 1
- 设 canvas.width/height = clientRect.width/height × dpr,再 ctx.scale(dpr, dpr)
- 所有事件坐标(clientX/clientY)减去 canvas.getBoundingClientRect().left/top,再除以 dpr 得逻辑像素
- 禁用 touch-action: none 防止移动端误触发滚动或缩放
防抖与点距过滤:去掉冗余采样,提升响应感
系统高频上报触摸点(尤其 iOS),但密集点不仅无益,反而拖慢绘制、加重锯齿:
- 设置最小位移阈值(如 1.5px),新点与上一点距离不足即跳过
- 或设最小时间间隔(如 8ms),避免 CPU 过载导致延迟累积
- 注意:过滤不能过度——过疏会导致圆弧失真,建议结合位移+时间双条件判断


















