平移 translate

translate方法用于移动Canvas坐标系的原点位置,是变换操作中最基础也是最常用的方法。

基本语法

ctx.translate(x, y)
参数类型说明
xnumber水平方向的移动距离
ynumber垂直方向的移动距离

工作原理

translate方法将坐标系的原点从当前位置移动到(x, y)位置。调用后,所有后续绑制的图形坐标都是相对于新原点的。

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

// 默认原点在(0, 0)
ctx.fillRect(0, 0, 50, 50)  // 绑制在画布左上角

// 平移原点到(100, 50)
ctx.translate(100, 50)

// 现在原点在(100, 50)
ctx.fillRect(0, 0, 50, 50)  // 绑制在画布(100, 50)位置

基本平移演示

平移变换基础

累积平移

translate调用会累积,每次调用都在当前原点基础上移动:

ctx.translate(50, 0)   // 原点: (50, 0)
ctx.translate(30, 20)  // 原点: (80, 20)
ctx.translate(20, 30)  // 原点: (100, 50)

累积平移演示

累积平移效果

使用save/restore

使用save和restore可以隔离平移变换:

// 保存当前状态
ctx.save()

// 平移并绑制
ctx.translate(100, 100)
ctx.fillRect(0, 0, 50, 50)

// 恢复状态(平移被撤销)
ctx.restore()

// 此时原点回到(0, 0)
ctx.fillRect(0, 0, 50, 50)

save/restore演示

使用save/restore隔离变换

实际应用场景

1. 简化绑制坐标

当图形需要绑制在特定位置时,translate可以简化坐标计算:

// 不使用translate
function drawHouse(ctx, x, y) {
  ctx.fillRect(x, y, 100, 80)
  ctx.beginPath()
  ctx.moveTo(x, y)
  ctx.lineTo(x + 50, y - 50)
  ctx.lineTo(x + 100, y)
  ctx.fill()
}

// 使用translate
function drawHouse(ctx) {
  ctx.fillRect(0, 0, 100, 80)
  ctx.beginPath()
  ctx.moveTo(0, 0)
  ctx.lineTo(50, -50)
  ctx.lineTo(100, 0)
  ctx.fill()
}

// 调用时
ctx.save()
ctx.translate(100, 100)
drawHouse(ctx)
ctx.restore()

2. 绘制重复图案

function drawPattern() {
  for (let i = 0; i < 5; i++) {
    ctx.save()
    ctx.translate(i * 80, 0)
    drawShape()
    ctx.restore()
  }
}

3. 相对定位

// 绘制一个由多个部分组成的对象
function drawCharacter(x, y) {
  ctx.save()
  ctx.translate(x, y)
  
  // 身体(相对于角色中心)
  ctx.fillRect(-15, -20, 30, 40)
  
  // 头部
  ctx.beginPath()
  ctx.arc(0, -30, 15, 0, Math.PI * 2)
  ctx.fill()
  
  ctx.restore()
}

实际应用演示

translate简化绑制

负值平移

translate可以使用负值,将原点向左或向上移动:

ctx.translate(-50, -50)  // 原点向左上移动

负值平移演示

负值平移

注意事项

变换累积

// 错误:忘记累积效应
for (let i = 0; i < 5; i++) {
  ctx.translate(50, 0)
  ctx.fillRect(0, 0, 30, 30)
}
// 结果:矩形位置分别是 50, 100, 150, 200, 250

// 正确:使用save/restore或setTransform
for (let i = 0; i < 5; i++) {
  ctx.save()
  ctx.translate(50 + i * 50, 0)
  ctx.fillRect(0, 0, 30, 30)
  ctx.restore()
}

性能考虑

// 频繁save/restore可能影响性能
// 对于简单场景,可以使用setTransform重置
ctx.setTransform(1, 0, 0, 1, x, y)  // 直接设置平移

小数坐标

// translate支持小数,但可能导致模糊
ctx.translate(10.5, 20.5)