绘制矩形

矩形是Canvas中最基础的图形,也是唯一可以直接绑制而不需要路径的形状。

三种矩形方法

Canvas提供了三个绑制矩形的方法:

方法说明
fillRect()绑制填充矩形
strokeRect()绑制描边矩形
clearRect()清除矩形区域

fillRect 填充矩形

语法

ctx.fillRect(x, y, width, height)

参数

参数说明
x矩形左上角x坐标
y矩形左上角y坐标
width矩形宽度
height矩形高度

示例

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')

// 基础填充矩形
ctx.fillStyle = '#3498db'
ctx.fillRect(50, 50, 200, 100)

// 不同颜色
ctx.fillStyle = '#e74c3c'
ctx.fillRect(50, 200, 200, 100)

// 半透明矩形
ctx.fillStyle = 'rgba(46, 204, 113, 0.5)'
ctx.fillRect(100, 100, 200, 150)

strokeRect 描边矩形

语法

ctx.strokeRect(x, y, width, height)

示例

// 基础描边矩形
ctx.strokeStyle = '#333'
ctx.lineWidth = 2
ctx.strokeRect(300, 50, 200, 100)

// 粗边框
ctx.strokeStyle = '#9b59b6'
ctx.lineWidth = 5
ctx.strokeRect(300, 200, 200, 100)

// 虚线边框
ctx.setLineDash([10, 5])
ctx.strokeStyle = '#1abc9c'
ctx.lineWidth = 2
ctx.strokeRect(300, 350, 200, 100)
ctx.setLineDash([])  // 重置虚线

填充+描边

// 先填充后描边
ctx.fillStyle = '#f1c40f'
ctx.fillRect(50, 400, 200, 100)

ctx.strokeStyle = '#f39c12'
ctx.lineWidth = 3
ctx.strokeRect(50, 400, 200, 100)

clearRect 清除矩形

// 绑制一个矩形
ctx.fillStyle = '#3498db'
ctx.fillRect(50, 50, 300, 200)

// 清除中间区域
ctx.clearRect(100, 100, 200, 100)

绘制圆角矩形

Canvas没有内置的圆角矩形方法,需要手动实现。

方法1:使用arcTo

function roundRect(ctx, x, y, width, height, radius) {
  ctx.beginPath()
  ctx.moveTo(x + radius, y)
  ctx.arcTo(x + width, y, x + width, y + height, radius)
  ctx.arcTo(x + width, y + height, x, y + height, radius)
  ctx.arcTo(x, y + height, x, y, radius)
  ctx.arcTo(x, y, x + width, y, radius)
  ctx.closePath()
}

// 填充圆角矩形
ctx.fillStyle = '#2ecc71'
roundRect(ctx, 50, 50, 200, 100, 15)
ctx.fill()

// 描边圆角矩形
ctx.strokeStyle = '#27ae60'
ctx.lineWidth = 3
roundRect(ctx, 300, 50, 200, 100, 20)
ctx.stroke()

方法2:支持不同圆角

function roundRect(ctx, x, y, width, height, radii) {
  // radii可以是数字或数组[topLeft, topRight, bottomRight, bottomLeft]
  if (typeof radii === 'number') {
    radii = [radii, radii, radii, radii]
  }
  
  const [tl, tr, br, bl] = radii
  
  ctx.beginPath()
  ctx.moveTo(x + tl, y)
  ctx.lineTo(x + width - tr, y)
  ctx.arcTo(x + width, y, x + width, y + tr, tr)
  ctx.lineTo(x + width, y + height - br)
  ctx.arcTo(x + width, y + height, x + width - br, y + height, br)
  ctx.lineTo(x + bl, y + height)
  ctx.arcTo(x, y + height, x, y + height - bl, bl)
  ctx.lineTo(x, y + tl)
  ctx.arcTo(x, y, x + tl, y, tl)
  ctx.closePath()
}

// 不同圆角
ctx.fillStyle = '#9b59b6'
roundRect(ctx, 50, 200, 200, 100, [30, 10, 30, 10])
ctx.fill()

实际应用

绘制按钮

function drawButton(ctx, x, y, width, height, text, bgColor, textColor) {
  // 按钮背景
  ctx.fillStyle = bgColor
  roundRect(ctx, x, y, width, height, 8)
  ctx.fill()
  
  // 按钮文字
  ctx.fillStyle = textColor
  ctx.font = '16px Arial'
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  ctx.fillText(text, x + width / 2, y + height / 2)
}

drawButton(ctx, 50, 350, 120, 40, '点击按钮', '#3498db', '#fff')
drawButton(ctx, 200, 350, 120, 40, '取消', '#95a5a6', '#fff')
drawButton(ctx, 350, 350, 120, 40, '确认', '#2ecc71', '#fff')

绘制卡片

function drawCard(ctx, x, y, width, height, title, content) {
  // 卡片阴影
  ctx.shadowColor = 'rgba(0, 0, 0, 0.1)'
  ctx.shadowBlur = 10
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 4
  
  // 卡片背景
  ctx.fillStyle = '#fff'
  roundRect(ctx, x, y, width, height, 10)
  ctx.fill()
  
  // 重置阴影
  ctx.shadowColor = 'transparent'
  ctx.shadowBlur = 0
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
  
  // 标题
  ctx.fillStyle = '#333'
  ctx.font = 'bold 18px Arial'
  ctx.fillText(title, x + 20, y + 35)
  
  // 内容
  ctx.fillStyle = '#666'
  ctx.font = '14px Arial'
  ctx.fillText(content, x + 20, y + 65)
}

drawCard(ctx, 50, 450, 300, 120, '卡片标题', '这是卡片的内容描述')

常见问题

问题1:矩形超出画布

// 超出部分会被裁剪,不会报错
ctx.fillRect(350, 250, 200, 200)  // 部分在画布外

问题2:负宽高

// 负值会反向绘制
ctx.fillRect(200, 200, -100, -50)  // 从(200,200)向左上绘制

问题3: lineWidth对fillRect的影响

// fillRect不受lineWidth影响
ctx.lineWidth = 10
ctx.fillRect(50, 50, 100, 50)  // 矩形大小不变

// strokeRect受lineWidth影响
ctx.strokeRect(200, 50, 100, 50)  // 边框会向外扩展