DESIGN NOTES
为什么值得收藏
- 中间点补回手指快速划动时系统会丢点,需在两采样点间按距离插值补点(如间距超过 4px 即插入),避免折线断笔
- 曲线平滑用二次/三次贝塞尔连接补点后的轨迹,平滑系数适中,过度平滑会糊掉笔锋细节
- 跟手低延迟绘制直接在 touchmove/pointermove 中渲染,优先离屏 canvas 保证帧率
UI 组件
结合原始资料,按需应用到自己的设计中。
实现一个手写笔迹平滑画布(原生 HTML/CSS/JS,零依赖,单文件交付):
【效果描述】用户用手指或鼠标在画布上书写/涂鸦时,笔迹跟手无延迟、连续不断笔:即使快速划动导致系统采样丢点,轨迹也能自动补全为平滑连贯的曲线,转角圆润自然,且保留笔锋细节不糊成一团;慢速书写时线条细腻,快速甩笔时线条流畅无折角锯齿。整体呈现接近真实纸笔的书写手感,适用于签名、涂鸦、批注等场景。
【交互参数】
- 触发条件:pointerdown 起笔,pointermove 持续采样绘制,pointerup/pointercancel/pointerleave 收笔;优先使用 Pointer Events,退化为 touch/mouse 事件。
- 补点插值:相邻两个原始采样点的欧氏距离超过 4px 时,按线性插值在中间插入补点,使补点后的相邻间距不超过 4px;每次 move 事件内若有 coalesced events(getCoalescedEvents)须全部消费,不可只取最后一个。
- 曲线平滑:不使用原始点直连折线;以补点序列中相邻两点的中点作为二次贝塞尔曲线的端点、原始点作为控制点连接轨迹(quadraticCurveTo 中点平滑法)。平滑窗口固定为 3 点,不做更大范围拟合,避免过度平滑丢失笔锋转折。
- 绘制参数:默认线宽 3px,lineCap/lineJoin 均为 round,默认墨色 #1a1a1a;DPR 适配:canvas 实际像素 = CSS 尺寸 × devicePixelRatio,ctx.scale(dpr, dpr) 后以 CSS 像素坐标绘制。
- 性能:pointermove 回调中直接增量绘制到离屏 canvas(OffscreenCanvas 或隐藏 canvas),再通过 requestAnimationFrame 合成到可见画布,单帧绘制耗时应低于 8ms;move 事件监听使用 passive: true。
- 边界情况:单点(down 后立即 up,无 move)须绘制一个直径等于线宽的圆点,不能不显示;pointerup 发生在画布外也要正确收笔(监听 setPointerCapture);窗口 resize 时按比例重绘已有笔迹而非清空;多指触控只响应第一个接触点,忽略其余 pointerId。
【使用示例】
1. 签名板:`<canvas class="uw-ink-canvas" data-uw-line-width="4" data-uw-color="#000"></canvas>` 配合 `new UWInkCanvas(el, { lineWidth: 4, color: '#000', maxGap: 4 })`,底部放"清除""确认"按钮调用实例的 clear() 与 toDataURL('image/png') 导出签名图。
2. 笔记批注层:在文章容器上叠一个 position:absolute 的同尺寸画布,pointer-events 由开关按钮控制;`new UWInkCanvas(el, { color: '#d93025', lineWidth: 2 })` 实现红笔圈画。颜色、线宽、补点阈值均可按项目替换。
【实现要点】
1. 初始化:读取 canvas CSS 尺寸与 DPR,设置实际像素并 scale;创建离屏 canvas 作为持久笔迹层,可见画布每帧仅做 drawImage 合成(或直接以可见 canvas 绘制、离屏层备份,二选一并在注释说明)。
2. 起笔:pointerdown 记录当前点为 lastPoint,调用 setPointerCapture,将点压入缓冲区;若无后续 move 即 up,画圆点。
3. 采样补点:pointermove 中遍历 getCoalescedEvents()(不支持则退回 event 本身),对每个采样点计算与 lastPoint 的距离,若 > 4px(maxGap)则按间距等分插入补点,全部进入待绘队列。
4. 平滑绘制:维护最近 3 个点的滑动窗口,每加入新点,以上一段中点为起点、lastPoint 为控制点、新段中点为终点调用 quadraticCurveTo,stroke 到离屏层;首段退化为 moveTo+lineTo。
5. 合成:requestAnimationFrame 循环将离屏层合成到可见画布;收笔时 flush 队列并结束当前路径。
6. 对外 API:clear() 清空两层画布;undo() 可选——以每次笔画为单位快照离屏层(最多保留 20 步);toDataURL() 导出;destroy() 移除全部监听。
7. resize:监听容器尺寸变化,将旧笔迹 drawImage 缩放绘制到新尺寸离屏层。
【质量要求】
- 不污染全局样式:所有样式限定在组件容器内,类名一律加 uw- 前缀(如 uw-ink-canvas、uw-ink-toolbar),不写全局 * 或 body 选择器;canvas 设置 touch-action: none 防止滚动冲突。
- prefers-reduced-motion:媒体查询命中时跳过 requestAnimationFrame 合成循环,改为 move 中直接同步绘制,并禁用任何入场/收笔过渡动画。
- 注释标出可调参数:maxGap(默认 4px 补点阈值)、lineWidth(默认 3)、color(默认 #1a1a1a)、平滑窗口大小(默认 3 点)、undo 快照上限(默认 20),均在配置对象与关键代码处用注释注明"可调"。
【参考资源】
- 资料详情:https://ui.undoai.cn/components/smooth-ink-canvas/
- 效果快照:https://ui.undoai.cn/components/smooth-ink-canvas/cover.png
- Demo 源码:https://ui.undoai.cn/components/smooth-ink-canvas/demo.html将提示词与你的页面背景、技术栈和目标尺寸一起交给代码助手。实现后对照原图检查布局和状态,再验证键盘、触控和减少动态效果。
展开后加载源代码
查看 Markdown 全文,复制或下载 design.md 后交给开发者使用。
# 手写笔迹平滑 — design.md 内容版本:sha256:b15b8a12b21f97d7504014c0ea8c8c9d7d31ba2583208834d9b6baec107d1f1e 本文件由当前元数据、实现摘要和实际文件列表确定性生成。元数据记录是资料声明;未提供的数值不作推断。实现建议须在后续开发中选择和验收。 ## 元数据记录 - 资产:components/smooth-ink-canvas;语义类型:interaction。 - 分类:交互模式。 - 标签:画布手写、补点插值、曲线平滑、防断笔。 - 场景:手写签名、涂鸦画板、笔记批注、白板协作。 - 平台:未提供。 - 风格:未提供。 ### 亮点声明 - 中间点补回:手指快速划动时系统会丢点,需在两采样点间按距离插值补点(如间距超过 4px 即插入),避免折线断笔 - 曲线平滑:用二次/三次贝塞尔连接补点后的轨迹,平滑系数适中,过度平滑会糊掉笔锋细节 - 跟手低延迟:绘制直接在 touchmove/pointermove 中渲染,优先离屏 canvas 保证帧率 ### 实际文件与参考资源 - `cover.png`(sha256:bce0cf18152d8edd230a6e14d45636c504b09e110a43d99eac08d2652a8de54b) - `demo.html`(sha256:7c9c707093cb00b2394792098f56d9eff04911108f66107b7d5e8ec30a3c03ec) - `meta.yml` - 实现摘要:sha256:7c9c707093cb00b2394792098f56d9eff04911108f66107b7d5e8ec30a3c03ec。 ## 未提供 - 未结构化记录的精确色值、字号、间距、断点、动效时长与状态转换参数不作推断;亮点中的数值属于元数据声明,demo 的存在与摘要不代表浏览器行为已验收。 ## 实现建议 - 按正常、悬停、聚焦、激活、禁用、加载、成功和错误状态定义适用的状态表。 - 使用语义化元素,验证键盘操作、焦点可见性、触控目标和减少动效偏好。 - 以 demo.html 为实现参考,逐项验证交互、窄屏布局、文本溢出和错误恢复;具体参数由实现与验收确认。
在完整提示词后补充你的要求;生成提示词不会创建新资产。
DESIGN NOTES
GOOD FOR