使用canvas封装一个绘制圆角矩形的方法
- 代码
- 原理
- 思路
- 分析
- 讲解
- 缺陷
- 改进
- 改进圆角非正规圆角的问题
- 改进后的代码实现的圆角
- 改进圆角过大的问题
- 总结
- 完整代码
在canvas中绘制一个矩形是非常简单的,使用canvas的rect()方法即可,但是没有办法绘制一个带圆角的矩形,如图:
代码
class DrawBoard extends BasicCanvas{
constructor(c){
super(c)
}
// 如何绘制带圆角的矩形
createRect(x,y,w,h,r = 0,{width,stroke,fill}={}){
r > 1/2*w ? r = 1/2*w : null
let x1 = x + r, x2 = x + w - r, x3 = x + w
let y1 = y + r, y2 = y + h -r, y3 = y + h
this.begin()
.start(x+1/2*w,y)
.link(x2, y)
.qbc(x3, y, x3, y1)
.link(x3,y2)
.qbc(x3, y3, x2, y3)
.link(x1, y3)
.qbc(x, y3, x, y2)
.link(x, y1)
.qbc(x, y, x1, y)
.end()
.lineStyle(width)
.stroke(stroke)
.fill(fill)
}
}
上面的代码是基于前几期写的玩转canvas系列封装的BasicCanvas类,有兴趣的可以去看一下,现在这个类是DrawBoard类,主要是用于封装一些图形方法
原理
思路
绘制一个圆角的矩形,主要使用的是canvas中的path路径方法,以及二次贝塞尔曲线方法,主要思路是直线的部分使用lineTo方法,曲线部分使用二次贝塞尔曲线方法(下面简称称为 qbc)
分析
根据上面的思路,我们大致可以将矩形分割为这几个部分(见下图),横轴的部分主要有四个区域x,x1,x2,x3,纵轴的区域是y,y1,y2,y3。
x,y是需要我们传入的参数,主要用于定义矩形左上角在canvas画布中的位置
x1 = x + r
x2 = x + w - r
x3 = x + w
y1 = y + r
y2 = y + h - r
y3 = y + h
其中 r 是圆角的半径,w 是矩形的宽,h 是矩形的高
讲解
首先需要定义起点
起点不应定义为左上角,应定义在矩形上方的中心,也是下图标定的地方。
this.begin()
// 起点坐标(x+1/2w, y+1/2h)
.start(x+1/2*w,y)
// 然后连接到点(x2, y)
.link(x2, y)
// 使用qbc方法,控制点(x3, y)结束点(x3, y1)
.qbc(x3, y, x3, y1)
// 然后连接到点(x3,y2)
.link(x3,y2)
// 使用qbc方法,控制点(x3, y3)结束点(x2, y3)
.qbc(x3, y3, x2, y3)
// 然后连接到点(x1, y3)
.link(x1, y3)
// 使用qbc方法,控制点(x, y3)结束点(x, y2)
.qbc(x, y3, x, y2)
// 然后连接到点(x, y1)
.link(x, y1)
// 使用qbc方法,控制点(x, y)结束点(x1, y)
.qbc(x, y, x1, y)
// 最后结束
.end()
.lineStyle(width)
.stroke(stroke)
.fill(fill)
看下图
缺陷
这个方法其实是有一定缺陷的,也就是使用qbc方法实现的圆角并非真正的圆角,我们将其圆角设为宽度的一半的时候,这个图像展现的应该是一个圆,但实际图像并非正规的圆
改进
改进圆角非正规圆角的问题
将使用qbc方法制作圆角的方法改成使用arc方法来制作圆角,这样即可实现真正的圆角
this.begin()
// 开始的点还是上方中心点
.start(x+1/2*w,y)
.link(x2, y)
// 使用四分之一的圆做圆角,起始角度是3/2*pi,结束角度是0
.circular(x2, y1, r, 3/2*pi, 0, false)
.link(x3,y2)
// 使用四分之一的圆做圆角,起始角度是0,结束角度是1/2*pi
.circular(x2, y2, r, 0, 1/2*pi, false)
.link(x1, y3)
// 使用四分之一的圆做圆角,起始角度是1/2*pi,结束角度是pi
.circular(x1, y2, r, 1/2*pi, pi, false)
.link(x, y1)
// 使用四分之一的圆做圆角,起始角度是pi,结束角度是3/2*pi
.circular(x1, y1, r, pi, 3/2*pi, false)
.end()
这里使用的circlar是自己封装的绘制圆形的方法,与arc()方法传递的参数几乎相同,只是我的方法可以链式调用使用起来更加便捷。
改进后的代码实现的圆角
这样就是很正规的圆角了
并且由于传入的圆角半径不能超过其最短边的一半,否则就会这样
改进圆角过大的问题
因此我们需要加上短边判断
首先判断出短边,然后判断短边的一半与圆角的大小关系
w >= h ? r > 1/2*h ? r = 1/2*h : null : r > 1/2*w ? r = 1/2*w : null
改进后
这样就是正常的圆角了
总结
实现圆角矩形的方法起始有多种,有兴趣的童鞋可以自己发挥一下脑洞,只要判断好直线与圆角的绘制就可以实现了。
完整代码
createRect(
x, // 矩形左上角x坐标
y, // 矩形左上角y坐标
w, // 矩形宽
h, // 矩形高
r = 0, // 圆角半径
{width,stroke,fill}={} // 样式 边框宽度,边框颜色,填充颜色
){
w >= h ? r > 1/2*h ? r = 1/2*h : null : r > 1/2*w ? r = 1/2*w : null
console.log(r)
let x1 = x + r, x2 = x + w - r, x3 = x + w
let y1 = y + r, y2 = y + h -r, y3 = y + h
let pi = Math.PI
this.begin()
.start(x+1/2*w,y)
.link(x2, y)
// .qbc(x3, y, x3, y1)
.circular(x2, y1, r, 3/2*pi, 0, false)
.link(x3,y2)
// .qbc(x3, y3, x2, y3)
.circular(x2, y2, r, 0, 1/2*pi, false)
.link(x1, y3)
// .qbc(x, y3, x, y2)
.circular(x1, y2, r, 1/2*pi, pi, false)
.link(x, y1)
// // .qbc(x, y, x1, y)
.circular(x1, y1, r, pi, 3/2*pi, false)
.end()
.lineStyle(width)
.stroke(stroke)
.fill(fill)
}