【canvas學習筆記六】狀態保存和變換

save()和restore()

save()
保存當前狀態,將當前canvas的狀態存入棧中。
restore()
恢復以前save的一個狀態,將以前的狀態從棧中彈出。javascript

保存的當前狀態包含如下信息:java

  • 變換(平移、旋轉、縮放)
  • 屬性: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled
  • 剪裁路徑

save()和restore()的用處就是有時候用canvas繪圖會通過不少操做,而後能夠用restore()直接恢復原先的狀態,而不用再變換到原來的狀態。這個API在須要進行不少變換的時候特別有用。
好比說在一開始先用save()保存了canvas最早的狀態,也就是沒通過任何操做的狀態,而後開始用canvas繪圖API繪圖,中間對strokeStyle、lineWidth、globalAlpha等不少屬性進行了修改,還進行了平移、旋轉等等變換操做,這時,若是又要從新再畫某個圖形,而畫這個圖形要變換回原來最早的狀態才方便畫,那麼直接restore()變回最初保存的狀態就行,不然,又要從新平移、旋轉,對各類屬性賦值,才變回須要的狀態,會很是麻煩。而save()和restore()兩行就解決了這個問題。canvas

例子

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  ctx.fillRect(0, 0, 150, 150);   // Draw a rectangle with default settings
  ctx.save();                  // Save the default state
 
  ctx.fillStyle = '#09F';      // Make changes to the settings
  ctx.fillRect(15, 15, 120, 120); // Draw a rectangle with new settings

  ctx.save();                  // Save the current state
  ctx.fillStyle = '#FFF';      // Make changes to the settings
  ctx.globalAlpha = 0.5; 
  ctx.fillRect(30, 30, 90, 90);   // Draw a rectangle with new settings

  ctx.restore();               // Restore previous state
  ctx.fillRect(45, 45, 60, 60);   // Draw a rectangle with restored settings

  ctx.restore();               // Restore original state
  ctx.fillRect(60, 60, 30, 30);   // Draw a rectangle with restored settings
}

結果

image

平移

translate(x, y)
將canvas沿x軸平移x個單位,沿y軸平移y個單位。動畫

image

平移是會移動畫布的,是畫布的位置變了。3d

例子

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  for (var i = 0; i < 3; i++) {
    for (var 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();
    }
  }
}

結果

image

旋轉

rotate(angle)
以原點(0, 0)爲中心點,旋轉angle弧度。rest

若是要以畫布的中心點爲旋轉點,須要用translate()平移畫布。
旋轉也是針對畫布的。code

例子

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  
  // left rectangles, rotate from canvas origin
  ctx.save();
  // blue rect
  ctx.fillStyle = '#0095DD';
  ctx.fillRect(30, 30, 100, 100); 
  ctx.rotate((Math.PI / 180) * 25);
  // grey rect
  ctx.fillStyle = '#4D4E53';
  ctx.fillRect(30, 30, 100, 100);
  ctx.restore();

  // right rectangles, rotate from rectangle center
  // draw blue rect
  ctx.fillStyle = '#0095DD';
  ctx.fillRect(150, 30, 100, 100);  
  
  ctx.translate(200, 80); // translate to rectangle center 
                          // x = x + 0.5 * width
                          // y = y + 0.5 * height
  ctx.rotate((Math.PI / 180) * 25); // rotate
  ctx.translate(-200, -80); // translate back
  
  // draw grey rect
  ctx.fillStyle = '#4D4E53';
  ctx.fillRect(150, 30, 100, 100);
}

結果

image

縮放

scale(x, y)
在水平方向縮放x個單位,在垂直方向縮放y個單位。orm

x, y能夠是負數,若是是負數的話,圖片就會呈鏡像。好比這行代碼translate(0,canvas.height); scale(1,-1); 就將canvas垂直翻轉,座標原點變成了左下角。blog

function draw() {
  var ctx = document.getElementById('canvas').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);
}

結果

image

變換矩陣

transform(a, b, c, d, e, f)
將當前的變換矩陣乘上 [a, b, c, d, e, f, 0, 0, 1] (是個3X3的矩陣)。圖片

各個參數表示的變換以下:
a (m11)
水平縮放。
b (m12)
水平斜切。
c (m21)
垂直斜切。
d (m22)
垂直縮放。
e (dx)
水平平移。
f (dy)
垂直平移。
要實現斜切的話,只能用變換矩陣。

setTransform(a, b, c, d, e, f)
重設當前變換矩陣,並進行變換。
resetTransform()
將當前矩陣設置爲同等變換矩陣。至關於這行ctx.setTransform(1, 0, 0, 1, 0, 0);

例子

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  var sin = Math.sin(Math.PI / 6);
  var cos = 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);
    ctx.transform(cos, sin, -sin, cos, 0, 0);
  }
  
  ctx.setTransform(-1, 0, 0, 1, 100, 100);
  ctx.fillStyle = 'rgba(255, 128, 255, 0.5)';
  ctx.fillRect(0, 50, 100, 100);
}

結果

image

相關文章
相關標籤/搜索