绘制多边形

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