Canvas无原生ctx.roundRect(),需用arcTo()或arc()手动构建路径:arcTo适合统一半径,自动计算切线圆弧;arc支持四角独立半径,需逐角指定圆心与角度;封装应返回ctx实现链式调用,并注意lineWidth、绘制顺序及负尺寸处理。

Canvas 本身没有 ctx.roundRect() 这样的原生方法,绘制圆角矩形必须靠手动构建路径。核心不是“画什么”,而是“怎么连”——用 arcTo() 或 arc() 把四条直线和四个圆弧无缝拼成闭合轮廓。封装得好,一行调用就能填色、描边、支持独立半径;封装不好,每次都要重写十几行路径逻辑。
用 arcTo 实现简洁抗锯齿路径
arcTo() 是最常用也最稳健的选择:它自动计算切线圆弧,代码短、渲染顺滑、边界容错强。关键在于理解它的参数逻辑——它不指定圆心,而是靠两个“切点”和半径推导出弧线。
- 起点设在左上角水平偏移处:
moveTo(x + radius, y) - 每段
arcTo(x1, y1, x2, y2, radius)的前两个坐标是“下一个角的顶点”,第三个是“当前角的外顶点” - 必须做半径校验:若
radius > width/2或radius > height/2,直接截断为最大允许值,避免路径塌陷 - 最后一定要调用
closePath(),否则 fill/stroke 可能失效
支持四角独立半径的 arc 版封装
当需要左上 4px、右上 8px、右下 12px、左下 6px 这类差异化设计时,arc() 更可控:它明确指定圆心、起止角度,适合逐角定制。
- 把半径数组标准化:支持数字(统一)、长度为 1/2/3/4 的数组,自动映射为 [tl, tr, br, bl]
- 每个角单独画一段
arc(cx, cy, r, start, end),再用lineTo()补直边 - 注意角度单位是弧度,
Math.PI / 2对应 90°,顺时针绘制推荐设anticlockwise = false - 起点建议从左上角内侧开始(
x + r1, y),避免首段弧线错位
链式调用与上下文复用设计
真正提升开发效率的封装,不只是函数,而是让路径可复用、可组合、可链式操作。
- 返回
ctx本身(或包装对象),支持连续调用:roundRect(...).fill().stroke() - 内部不执行
fill()或stroke(),只建路径,把渲染决策留给调用方 - 可扩展选项参数:比如
{ fill: '#fff', stroke: '#333', lineWidth: 2 },避免重复设置 ctx 状态 - 兼容现代 Canvas 工具链(如 ZRender、Konva),路径生成逻辑可直接注入 shape 描述对象
避坑要点:那些悄悄吃掉你半天的细节
看似简单的圆角矩形,实际藏着几个高频翻车点:
-
lineWidth 影响视觉尺寸:描边会向路径两侧延伸,若需精确宽高,得在传入 width/height 前减去
lineWidth -
fill() 和 stroke() 顺序有讲究:先 stroke 再 fill 可能盖住边框;推荐先 fill 后 stroke,或用
globalCompositeOperation控制混合 -
负数宽高要翻转起点:当 width 或 height 为负,需动态调整
x或y,否则矩形飞走 - 不要用 lineJoin="round":那只是拐角圆润化,不是真正的圆角矩形,且对 fillRect 无效、对 strokeRect 效果不可控









