# 变形

到目前为止,我们只是根据我们的需要使用默认的网格,改变整个画布的大小。

变形是一种更强大的方法,可以将原点移动到另一点、对网格进行旋转和缩放。

# 状态的保存和恢复

  • save()
  • restore()
function draw() {
  const canvas = document.getElementById("demo8_0");
  const ctx = canvas.getContext("2d");
  ctx.fillRect(0, 0, 150, 150); // 使用默认设置绘制一个矩形
  ctx.save(); // 保存默认状态

  ctx.fillStyle = "#09F"; // 在原有配置基础上对颜色做改变
  ctx.fillRect(15, 15, 120, 120); // 使用新的设置绘制一个矩形

  ctx.save(); // 保存当前状态
  ctx.fillStyle = "#FFF"; // 再次改变颜色配置
  ctx.globalAlpha = 0.5;
  ctx.fillRect(30, 30, 90, 90); // 使用新的配置绘制一个矩形

  ctx.restore(); // 重新加载之前的颜色状态
  ctx.fillRect(45, 45, 60, 60); // 使用上一次的配置绘制一个矩形

  ctx.restore(); // 加载默认颜色配置
  ctx.fillRect(60, 60, 30, 30); // 使用加载的配置绘制一个矩形
}

# 移动

translate() 它用来移动 canvas 和它的原点到一个不同的位置。

TIP

在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。

function draw() {
  const canvas = document.getElementById("demo8_1");
  const ctx = canvas.getContext("2d");
  for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
      ctx.save();
      ctx.fillStyle = `rgb(${51 * i}, ${255 - 51 * i}, 255)`;
      ctx.translate(10 + j * 50, 10 + i * 50);
      ctx.fillRect(0, 0, 25, 25);
      ctx.restore();
    }
  }
}

# 旋转

rotate(deg) 它用于以原点为中心旋转 canvas。

function draw() {
  const ctx = document.getElementById("demo8_2").getContext("2d");
  ctx.translate(75, 75);
  for (var i = 1; i < 6; i++) {
    // Loop through rings (from inside to out)
    ctx.save();
    ctx.fillStyle = "rgb(" + 51 * i + "," + (255 - 51 * i) + ",255)";
    for (var j = 0; j < i * 6; j++) {
      // draw individual dots
      ctx.rotate((Math.PI * 2) / (i * 6));
      ctx.beginPath();
      ctx.arc(0, i * 12.5, 5, 0, Math.PI * 2, true);
      ctx.fill();
    }
    ctx.restore();
  }
}

# 缩放

接着是缩放。我们用它来增减图形在 canvas 中的像素数目,对形状,位图进行缩小或者放大。

scale(x, y)

scale方法可以缩放画布的水平和垂直的单位

function draw() {
  const ctx = document.getElementById("demo8_3").getContext("2d");
  // draw a simple rectangle, but scale it.
  ctx.save();
  ctx.scale(10, 3);
  ctx.fillRect(1, 10, 10, 10);
  ctx.restore();
  // mirror horizontally
  ctx.scale(-1, 1);
  ctx.font = "48px serif";
  ctx.fillText("MDN", -135, 120);
}

# 变形

transform

function draw() {
  const canvas =document.getElementById("demo8_4")
  canvas.width = 200
  canvas.height = 360
  const ctx = canvas.getContext("2d");
  const sin30 = Math.sin(Math.PI / 6);
  const cos30 = Math.cos(Math.PI / 6);
  // 移动中心点
  ctx.translate(100, 100);
  var c = 0;
  for (var i = 0; i <= 12; i++) {
    c = Math.floor((255 / 12) * i);
    ctx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
    ctx.fillRect(0, 0, 100, 10);
    // 顺时针旋转画布30度
    ctx.transform(cos30, sin30, -sin30, cos30, 0, 0);
  }
  // 不缩放 竖直方向进行倾斜 向下移动100 单位
  ctx.setTransform(1, 1, 0, 1, 0, 100);
  ctx.fillStyle = "rgba(255, 128, 255, 0.5)";
  ctx.fillRect(0, 50, 100, 100);
}