绘制三角形

Canvas绑制三角形详解,包括等边三角形、等腰三角形、直角三角形的绑制方法,包含多个交互式案例。 三角形是最简单的多边形,通过moveTo和lineTo组合可以绑制各种三角形。

三角形类型

类型特点绘制方式
等边三角形三边相等计算三个顶点
等腰三角形两边相等简化计算
直角三角形一个直角固定角度
任意三角形无特殊要求手动指定顶点

案例一:基本三角形

不同类型的三角形

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

// 等边三角形
ctx.beginPath()
ctx.moveTo(60, 30)
ctx.lineTo(30, 90)
ctx.lineTo(90, 90)
ctx.closePath()
ctx.fillStyle = '#e74c3c'
ctx.fill()

// 描边三角形
ctx.beginPath()
ctx.moveTo(150, 30)
ctx.lineTo(120, 90)
ctx.lineTo(180, 90)
ctx.closePath()
ctx.strokeStyle = '#3498db'
ctx.lineWidth = 3
ctx.stroke()

// 直角三角形
ctx.beginPath()
ctx.moveTo(220, 30)
ctx.lineTo(220, 90)
ctx.lineTo(280, 90)
ctx.closePath()
ctx.fillStyle = '#2ecc71'
ctx.fill()
</script>

代码解析

步骤说明
moveTo设置起点
lineTo画线到其他顶点
closePath闭合路径
fill/stroke填充或描边

案例二:等边三角形函数

使用函数绑制等边三角形

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

function drawEquilateralTriangle(cx, cy, size, rotation, color, fill) {
  ctx.beginPath()
  
  for (let i = 0; i < 3; i++) {
    const angle = rotation + i * 2 * Math.PI / 3 - Math.PI / 2
    const x = cx + size * Math.cos(angle)
    const y = cy + size * Math.sin(angle)
    if (i === 0) ctx.moveTo(x, y)
    else ctx.lineTo(x, y)
  }
  
  ctx.closePath()
  
  if (fill) {
    ctx.fillStyle = color
    ctx.fill()
  } else {
    ctx.strokeStyle = color
    ctx.lineWidth = 2
    ctx.stroke()
  }
}

drawEquilateralTriangle(100, 100, 40, 0, '#e74c3c', true)
drawEquilateralTriangle(200, 100, 40, Math.PI / 6, '#3498db', true)
drawEquilateralTriangle(300, 100, 40, Math.PI / 3, '#2ecc71', true)
</script>

代码解析

技术说明
中心点三角形中心坐标
角度计算i * 2π / 3 均分三个顶点
旋转添加rotation参数
-π/2从顶部开始绘制

案例三:三角形图案

三角形组成的图案

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

function drawTriangle(x1, y1, x2, y2, x3, y3, color) {
  ctx.beginPath()
  ctx.moveTo(x1, y1)
  ctx.lineTo(x2, y2)
  ctx.lineTo(x3, y3)
  ctx.closePath()
  ctx.fillStyle = color
  ctx.fill()
}

const colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6']
const size = 35
const h = size * Math.sqrt(3) / 2

for (let row = 0; row < 4; row++) {
  for (let col = 0; col < 6; col++) {
    const x = 50 + col * size
    const y = 30 + row * h
    const colorIndex = (row + col) % colors.length
    
    // 交替绘制向上和向下的三角形
    if ((row + col) % 2 === 0) {
      drawTriangle(x, y, x + size, y, x + size / 2, y + h, colors[colorIndex])
    } else {
      drawTriangle(x + size / 2, y, x + size, y + h, x, y + h, colors[colorIndex])
    }
  }
}
</script>

代码解析

技术说明
高度计算h = size * √3 / 2
交替方向奇偶判断决定方向
颜色循环(row + col) % colors.length

案例四:旋转三角形动画

旋转三角形动画

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

let rotation = 0

const triangles = [
  { x: 80, y: 100, size: 40, color: '#e74c3c', speed: 1 },
  { x: 160, y: 100, size: 35, color: '#3498db', speed: -1.5 },
  { x: 240, y: 100, size: 45, color: '#2ecc71', speed: 2 },
  { x: 320, y: 100, size: 30, color: '#f39c12', speed: -1 }
]

function drawTriangle(t, rot) {
  ctx.beginPath()
  for (let i = 0; i < 3; i++) {
    const angle = rot + i * 2 * Math.PI / 3 - Math.PI / 2
    const x = t.x + t.size * Math.cos(angle)
    const y = t.y + t.size * Math.sin(angle)
    if (i === 0) ctx.moveTo(x, y)
    else ctx.lineTo(x, y)
  }
  ctx.closePath()
  ctx.fillStyle = t.color
  ctx.fill()
}

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  
  triangles.forEach(t => {
    drawTriangle(t, rotation * t.speed)
  })
  
  rotation += 0.02
  requestAnimationFrame(animate)
}

animate()
</script>

代码解析

技术说明
不同速度speed属性控制旋转速度
正负速度正数顺时针,负数逆时针
动画循环requestAnimationFrame

案例五:谢尔宾斯基三角形

谢尔宾斯基三角形(分形)

代码实现

<canvas id="myCanvas" width="400" height="200"></canvas>

<script>
const canvas = document.getElementById('myCanvas')
const ctx = canvas.getContext('2d')

function sierpinski(x1, y1, x2, y2, x3, y3, depth) {
  if (depth === 0) {
    ctx.beginPath()
    ctx.moveTo(x1, y1)
    ctx.lineTo(x2, y2)
    ctx.lineTo(x3, y3)
    ctx.closePath()
    ctx.fillStyle = '#3498db'
    ctx.fill()
    return
  }
  
  // 计算三边中点
  const mx1 = (x1 + x2) / 2
  const my1 = (y1 + y2) / 2
  const mx2 = (x2 + x3) / 2
  const my2 = (y2 + y3) / 2
  const mx3 = (x1 + x3) / 2
  const my3 = (y1 + y3) / 2
  
  // 递归绘制三个小三角形
  sierpinski(x1, y1, mx1, my1, mx3, my3, depth - 1)
  sierpinski(mx1, my1, x2, y2, mx2, my2, depth - 1)
  sierpinski(mx3, my3, mx2, my2, x3, y3, depth - 1)
}

// 绘制深度为4的谢尔宾斯基三角形
const size = 180
const h = size * Math.sqrt(3) / 2
const cx = 200
const cy = 150

sierpinski(cx, cy - h * 2/3, cx - size/2, cy + h/3, cx + size/2, cy + h/3, 4)
</script>

代码解析

技术说明
递归分形的核心思想
中点计算三边中点形成新三角形
深度控制depth决定递归层数