封装canvas上下文的核心是创建增强代理:自动适配像素比、防路径污染、语义化调用,同时保持原生api兼容性与可扩展性。

封装 Canvas 绘图上下文,核心不是“多写几个函数”,而是让 ctx 更聪明、更健壮、更贴近业务场景——它要能自动处理像素比、避免路径污染、支持语义化调用,并且不破坏原生能力的可扩展性。
从 ctx 出发,封装一层安全壳
直接操作原生 ctx 容易出错:忘记 beginPath() 导致路径叠加,漏掉 save()/restore() 引发样式污染,缩放后未适配 devicePixelRatio 造成模糊。封装第一步,就是创建一个增强版上下文代理:
- 构造时自动绑定 canvas 元素,并根据
window.devicePixelRatio设置canvas.width/height和 CSS 样式宽高 - 所有绘图方法(如
drawRect、drawCircle)内部默认调用beginPath()和closePath() - 提供
withStyle({ fill, stroke, lineWidth })方法,自动save()→ 设置 →restore(),避免状态泄漏
按图形类型封装可复用的绘制单元
不要把所有逻辑塞进一个“CanvasUtils”里。针对高频图形,拆成独立函数或类,每个只做一件事、接口清晰、参数合理:
-
roundRect(ctx, x, y, w, h, r, fill):自动处理圆角超出宽高的边界情况(如r = Math.min(r, w/2, h/2)) -
drawArrow(ctx, fromX, fromY, toX, toY, headSize = 10):内置箭头角度计算与路径生成,支持填充/描边双模式 -
drawAutoWrapText(ctx, text, x, y, maxWidth, lineHeight, opts):自动分行、支持居中/右对齐、返回实际渲染行数
封装交互与生命周期管理
当绘图需要响应鼠标/触摸(比如画板、选区、拖拽点),封装必须覆盖完整生命周期:
- 绑定事件时使用唯一符号(如
Symbol('canvas-handler'))标记监听器,便于精准解绑 - 提供
startListening()/stopListening()控制开关,而非隐式绑定 - 暴露
clear()(清空内容)、resetTransform()(重置变换矩阵)、destroy()(清理定时器、事件、图像引用)等明确语义的方法
保持与原生 API 的无缝衔接
封装不是隔绝底层,而是降低门槛、提升鲁棒性。好的封装应做到:
- 所有方法最后仍调用原生
ctx.xxx(),不拦截也不替换,确保新浏览器特性可立即使用 - 导出的函数/类都接受原始
ctx作为第一个参数,方便在任意上下文(Web Worker Canvas、小程序createCanvasContext、Node.js node-canvas)中复用 - 提供
getRawContext()方法随时取回原生 ctx,应对特殊需求











