Canvas绘制基本形状教程,学习矩形、圆形、直线等基础图形的绑制方法。Canvas提供了多种绑制基本形状的方法。掌握这些方法是创建复杂图形的基础。
| 形状 | 方法 | 说明 |
|---|---|---|
| 矩形 | fillRect / strokeRect | 唯一可直接绘制的形状 |
| 圆形 | arc + fill / stroke | 需要路径 |
| 椭圆 | ellipse | 需要路径 |
| 直线 | moveTo + lineTo | 需要路径 |
| 多边形 | 路径组合 | 需要路径 |
矩形是Canvas中唯一可以直接绑制的形状,不需要路径。
ctx.fillStyle = '#3498db'
ctx.fillRect(x, y, width, height)
ctx.strokeStyle = '#e74c3c'
ctx.lineWidth = 2
ctx.strokeRect(x, y, width, height)
ctx.clearRect(x, y, width, height)
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// 填充矩形
ctx.fillStyle = '#3498db'
ctx.fillRect(50, 50, 150, 100)
// 描边矩形
ctx.strokeStyle = '#e74c3c'
ctx.lineWidth = 3
ctx.strokeRect(250, 50, 150, 100)
// 填充+描边
ctx.fillStyle = '#2ecc71'
ctx.fillRect(50, 200, 150, 100)
ctx.strokeStyle = '#27ae60'
ctx.lineWidth = 2
ctx.strokeRect(50, 200, 150, 100)
圆形需要通过路径绑制。
ctx.beginPath() // 1. 开始路径
ctx.arc(x, y, radius, 0, Math.PI * 2) // 2. 绘制圆弧
ctx.fill() // 3. 填充或描边
ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise)
| 参数 | 说明 |
|---|---|
| x, y | 圆心坐标 |
| radius | 半径 |
| startAngle | 起始角度(弧度) |
| endAngle | 结束角度(弧度) |
| counterclockwise | 是否逆时针(可选,默认false) |
// 填充圆
ctx.beginPath()
ctx.arc(100, 100, 50, 0, Math.PI * 2)
ctx.fillStyle = '#9b59b6'
ctx.fill()
// 描边圆
ctx.beginPath()
ctx.arc(250, 100, 50, 0, Math.PI * 2)
ctx.strokeStyle = '#8e44ad'
ctx.lineWidth = 3
ctx.stroke()
// 半圆
ctx.beginPath()
ctx.arc(400, 100, 50, 0, Math.PI)
ctx.fillStyle = '#1abc9c'
ctx.fill()
使用ellipse方法绑制椭圆。
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle)
| 参数 | 说明 |
|---|---|
| x, y | 圆心坐标 |
| radiusX | 水平半径 |
| radiusY | 垂直半径 |
| rotation | 旋转角度(弧度) |
| startAngle | 起始角度 |
| endAngle | 结束角度 |
// 水平椭圆
ctx.beginPath()
ctx.ellipse(150, 200, 80, 40, 0, 0, Math.PI * 2)
ctx.fillStyle = '#e67e22'
ctx.fill()
// 垂直椭圆
ctx.beginPath()
ctx.ellipse(350, 200, 40, 80, 0, 0, Math.PI * 2)
ctx.fillStyle = '#d35400'
ctx.fill()
// 旋转45度的椭圆
ctx.beginPath()
ctx.ellipse(550, 200, 60, 30, Math.PI / 4, 0, Math.PI * 2)
ctx.strokeStyle = '#c0392b'
ctx.lineWidth = 2
ctx.stroke()
使用moveTo和lineTo绑制直线。
ctx.moveTo(x1, y1) // 移动到起点
ctx.lineTo(x2, y2) // 画线到终点
ctx.stroke() // 描边
// 单条直线
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(200, 150)
ctx.strokeStyle = '#333'
ctx.lineWidth = 2
ctx.stroke()
// 多条连续线
ctx.beginPath()
ctx.moveTo(250, 50)
ctx.lineTo(400, 50)
ctx.lineTo(400, 150)
ctx.lineTo(250, 150)
ctx.closePath() // 闭合路径
ctx.stroke()
三角形通过三条直线组成。
function drawTriangle(ctx, x1, y1, x2, y2, x3, y3, fill = true) {
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.lineTo(x3, y3)
ctx.closePath()
if (fill) {
ctx.fill()
} else {
ctx.stroke()
}
}
// 使用
ctx.fillStyle = '#16a085'
drawTriangle(ctx, 100, 50, 50, 150, 150, 150)
ctx.strokeStyle = '#2980b9'
ctx.lineWidth = 2
drawTriangle(ctx, 250, 50, 200, 150, 300, 150, false)
多边形由多条线段组成。
function drawPolygon(ctx, x, y, radius, sides, rotation = 0) {
ctx.beginPath()
for (let i = 0; i < sides; i++) {
const angle = (i * 2 * Math.PI / sides) + rotation
const px = x + radius * Math.cos(angle)
const py = y + radius * Math.sin(angle)
if (i === 0) {
ctx.moveTo(px, py)
} else {
ctx.lineTo(px, py)
}
}
ctx.closePath()
}
// 五边形
ctx.fillStyle = '#8e44ad'
drawPolygon(ctx, 100, 300, 50, 5)
ctx.fill()
// 六边形
ctx.fillStyle = '#27ae60'
drawPolygon(ctx, 250, 300, 50, 6)
ctx.fill()
// 八边形
ctx.fillStyle = '#e74c3c'
drawPolygon(ctx, 400, 300, 50, 8)
ctx.fill()
Canvas没有直接的圆角矩形方法,需要手动绑制。
function roundRect(ctx, x, y, width, height, radius) {
ctx.beginPath()
ctx.moveTo(x + radius, y)
ctx.lineTo(x + width - radius, y)
ctx.arcTo(x + width, y, x + width, y + radius, radius)
ctx.lineTo(x + width, y + height - radius)
ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
ctx.lineTo(x + radius, y + height)
ctx.arcTo(x, y + height, x, y + height - radius, radius)
ctx.lineTo(x, y + radius)
ctx.arcTo(x, y, x + radius, y, radius)
ctx.closePath()
}
// 使用
ctx.fillStyle = '#3498db'
roundRect(ctx, 50, 400, 200, 100, 20)
ctx.fill()
ctx.strokeStyle = '#2980b9'
ctx.lineWidth = 3
roundRect(ctx, 300, 400, 200, 100, 30)
ctx.stroke()
const data = [120, 200, 150, 80, 180, 100]
const barWidth = 50
const gap = 20
const startX = 50
const baseY = 350
// 绑制柱状图
data.forEach((value, index) => {
const x = startX + index * (barWidth + gap)
const height = value
const y = baseY - height
// 渐变色
const gradient = ctx.createLinearGradient(x, y, x, baseY)
gradient.addColorStop(0, '#3498db')
gradient.addColorStop(1, '#2980b9')
ctx.fillStyle = gradient
ctx.fillRect(x, y, barWidth, height)
// 数值标签
ctx.fillStyle = '#333'
ctx.font = '14px Arial'
ctx.textAlign = 'center'
ctx.fillText(value, x + barWidth / 2, y - 10)
})
// 基线
ctx.beginPath()
ctx.moveTo(startX - 10, baseY)
ctx.lineTo(startX + data.length * (barWidth + gap), baseY)
ctx.strokeStyle = '#333'
ctx.lineWidth = 1
ctx.stroke()