Canvas绑制多边形详解,包括正多边形、星形、不规则多边形的绑制方法,包含多个交互式案例。
多边形是由多条边组成的封闭图形。通过循环计算顶点坐标,可以绑制各种多边形。
多边形类型
| 类型 | 特点 | 绘制方式 |
|---|
| 正多边形 | 所有边相等 | 角度均分计算顶点 |
| 星形 | 凹多边形 | 交替内外半径 |
| 不规则多边形 | 边长不等 | 手动指定顶点 |
| 圆角多边形 | 圆角过渡 | arcTo方法 |
案例一:正多边形
不同边数的正多边形
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function drawPolygon(cx, cy, radius, sides, color) {
ctx.beginPath()
for (let i = 0; i < sides; i++) {
const angle = -Math.PI / 2 + i * 2 * Math.PI / sides
const x = cx + radius * Math.cos(angle)
const y = cy + radius * Math.sin(angle)
if (i === 0) ctx.moveTo(x, y)
else ctx.lineTo(x, y)
}
ctx.closePath()
ctx.fillStyle = color
ctx.fill()
}
drawPolygon(60, 100, 40, 3, '#e74c3c')
drawPolygon(150, 100, 40, 4, '#3498db')
drawPolygon(240, 100, 40, 5, '#2ecc71')
drawPolygon(330, 100, 40, 6, '#f39c12')
</script>
代码解析
| 参数 | 说明 |
|---|
| cx, cy | 多边形中心坐标 |
| radius | 外接圆半径 |
| sides | 边数 |
| -π/2 | 从顶部开始绘制 |
案例二:星形
不同角数的星形
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function drawStar(cx, cy, outerRadius, innerRadius, points, color) {
ctx.beginPath()
for (let i = 0; i < points * 2; i++) {
const radius = i % 2 === 0 ? outerRadius : innerRadius
const angle = -Math.PI / 2 + i * Math.PI / points
const x = cx + radius * Math.cos(angle)
const y = cy + radius * Math.sin(angle)
if (i === 0) ctx.moveTo(x, y)
else ctx.lineTo(x, y)
}
ctx.closePath()
ctx.fillStyle = color
ctx.fill()
}
drawStar(100, 100, 40, 20, 5, '#f1c40f')
drawStar(200, 100, 40, 15, 6, '#2ecc71')
drawStar(300, 100, 40, 18, 8, '#9b59b6')
</script>
代码解析
| 参数 | 说明 |
|---|
| outerRadius | 外半径(尖角) |
| innerRadius | 内半径(凹角) |
| points | 角数 |
| points * 2 | 总顶点数 |
案例三:不规则多边形
不规则多边形
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
const arrow = [
{ x: 50, y: 100 },
{ x: 80, y: 70 },
{ x: 80, y: 85 },
{ x: 130, y: 85 },
{ x: 130, y: 115 },
{ x: 80, y: 115 },
{ x: 80, y: 130 }
]
ctx.beginPath()
arrow.forEach((p, i) => {
if (i === 0) ctx.moveTo(p.x, p.y)
else ctx.lineTo(p.x, p.y)
})
ctx.closePath()
ctx.fillStyle = '#3498db'
ctx.fill()
const cross = [
{ x: 200, y: 50 },
{ x: 230, y: 50 },
{ x: 230, y: 80 },
{ x: 260, y: 80 },
{ x: 260, y: 120 },
{ x: 230, y: 120 },
{ x: 230, y: 150 },
{ x: 200, y: 150 },
{ x: 200, y: 120 },
{ x: 170, y: 120 },
{ x: 170, y: 80 },
{ x: 200, y: 80 }
]
ctx.beginPath()
cross.forEach((p, i) => {
if (i === 0) ctx.moveTo(p.x, p.y)
else ctx.lineTo(p.x, p.y)
})
ctx.closePath()
ctx.fillStyle = '#e74c3c'
ctx.fill()
</script>
代码解析
| 技术 | 说明 |
|---|
| 顶点数组 | 存储所有顶点坐标 |
| 遍历绘制 | 循环调用moveTo/lineTo |
| 爱心公式 | 参数方程绘制曲线 |
案例四:圆角多边形
圆角多边形
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function drawRoundedPolygon(cx, cy, radius, sides, cornerRadius, color) {
const points = []
for (let i = 0; i < sides; i++) {
const angle = -Math.PI / 2 + i * 2 * Math.PI / sides
points.push({
x: cx + radius * Math.cos(angle),
y: cy + radius * Math.sin(angle)
})
}
ctx.beginPath()
points.forEach((p, i) => {
const prev = points[(i - 1 + sides) % sides]
const next = points[(i + 1) % sides]
const v1x = prev.x - p.x
const v1y = prev.y - p.y
const v2x = next.x - p.x
const v2y = next.y - p.y
const len1 = Math.sqrt(v1x * v1x + v1y * v1y)
const len2 = Math.sqrt(v2x * v2x + v2y * v2y)
const cr = Math.min(cornerRadius, len1 / 2, len2 / 2)
const startX = p.x + v1x / len1 * cr
const startY = p.y + v1y / len1 * cr
const endX = p.x + v2x / len2 * cr
const endY = p.y + v2y / len2 * cr
ctx.lineTo(startX, startY)
ctx.arcTo(p.x, p.y, endX, endY, cr)
})
ctx.closePath()
ctx.fillStyle = color
ctx.fill()
}
drawRoundedPolygon(100, 100, 40, 5, 10, '#2ecc71')
drawRoundedPolygon(220, 100, 40, 6, 8, '#f39c12')
</script>
代码解析
| 技术 | 说明 |
|---|
| arcTo | 绘制圆角 |
| 向量计算 | 计算圆角起点和终点 |
| 半径限制 | 不能超过边长的一半 |
案例五:多边形动画
旋转多边形动画
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
let rotation = 0
const polygons = [
{ cx: 100, cy: 100, radius: 40, sides: 3, color: '#e74c3c', speed: 1 },
{ cx: 220, cy: 100, radius: 40, sides: 4, color: '#3498db', speed: -0.8 },
{ cx: 340, cy: 100, radius: 40, sides: 5, color: '#2ecc71', speed: 0.6 }
]
function drawPolygon(p, rot) {
ctx.beginPath()
for (let i = 0; i < p.sides; i++) {
const angle = rot + i * 2 * Math.PI / p.sides - Math.PI / 2
const x = p.cx + p.radius * Math.cos(angle)
const y = p.cy + p.radius * Math.sin(angle)
if (i === 0) ctx.moveTo(x, y)
else ctx.lineTo(x, y)
}
ctx.closePath()
ctx.fillStyle = p.color
ctx.fill()
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
polygons.forEach(p => {
drawPolygon(p, rotation * p.speed)
})
rotation += 0.02
requestAnimationFrame(animate)
}
animate()
</script>
代码解析
| 技术 | 说明 |
|---|
| 旋转角度 | 累加rotation变量 |
| 不同速度 | speed属性控制 |
| 正负速度 | 控制旋转方向 |
案例六:蜂窝图案
蜂窝图案
代码实现
<canvas id="myCanvas" width="400" height="200"></canvas>
<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')
function drawHexagon(cx, cy, radius, fillColor, strokeColor) {
ctx.beginPath()
for (let i = 0; i < 6; i++) {
const angle = i * Math.PI / 3
const x = cx + radius * Math.cos(angle)
const y = cy + radius * Math.sin(angle)
if (i === 0) ctx.moveTo(x, y)
else ctx.lineTo(x, y)
}
ctx.closePath()
if (fillColor) {
ctx.fillStyle = fillColor
ctx.fill()
}
if (strokeColor) {
ctx.strokeStyle = strokeColor
ctx.lineWidth = 1
ctx.stroke()
}
}
const size = 25
const h = size * Math.sqrt(3)
for (let row = 0; row < 5; row++) {
for (let col = 0; col < 10; col++) {
const x = 30 + col * size * 1.5 + (row % 2) * size * 0.75
const y = 30 + row * h * 0.5
drawHexagon(x, y, size - 2, 'rgba(52, 152, 219, 0.3)', '#3498db')
}
}
</script>
代码解析
| 技术 | 说明 |
|---|
| 六边形角度 | π/3 = 60度 |
| 偏移排列 | 奇数行偏移半个宽度 |
| 高度计算 | h = size * √3 |