blog.Ring.idv.tw

淺談Canvas - save/restore

淺談Canvas - save/restore


CanvasHTML5規格中的一部份,它允許你可以用程式來繪製一些2D圖形或是點陣圖,通常也被拿來製作HTML5遊戲之用,而本文主要介紹Canvas API中最常被初學者混淆的一組函式,它們分別為:「save()」和「restore()」,簡單來說~ 「save()」主要是用來保存目前Canvas的狀態,例如:style, lineWidth, font等,透過「save()」函式的呼叫它會將目前Canvas的狀態「Push」到「Stack」之中,而「restore()」函式就是從「Stack」來「Pop」出上一個Canvas的狀態,讀到這邊如果您已經了解「save/restore」的話,那非常恭禧你已經掌握要領了,反之~ 如果仍然有所疑惑的話,請看下面的範例介紹:

實作範例

本文將透過兩種不同的方式來實作出上圖的範例,以方便理解為何需要「save/restore」函式,使用它有何好處?

範例1 - 不採用save/restore

範例1完整的程式碼如下:(筆者假設您已經有基本的Canvas概念,所以會跳過一些基本的解說)

<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<canvas id="a_canvas" width="200" height="150"></canvas>
<script type="text/javascript">
  var canvas = document.getElementById("a_canvas");
  var ctx = canvas.getContext("2d");
  function drawRect(context, color) {
    context.fillStyle = color;
    context.fillRect(0, 0, 100, 30);
  }
  function rotateDeg(context, deg) {
    var rad = deg * Math.PI / 180;
    context.rotate(rad);
  }
  drawRect(ctx, "red");
  ctx.translate(100,30); 
  rotateDeg(ctx, 45);    
  drawRect(ctx, "blue");
  rotateDeg(ctx, 45);    
  ctx.translate(20, -100); 
  drawRect(ctx, "green");
</script>
</body></html>

P.S. 下述圖形的虛線都作為解說之用,並非繪製在Canvas上的線條

drawRect(ctx, "red");

透過自訂的「drawRect()」函式,然後在Canvas上繪製一個從座標點(0,0)的位置畫一個長為100px寬為30px的紅色矩形。

ctx.translate(100,30); 

將目前Canvas的基準點位置設為(100,30),如上圖所示。

P.S. Canvas基準點位置預設為左上角,和Flash座標系統一致。

rotateDeg(ctx, 45);
drawRect(ctx, "blue");

透過自訂的「rotateDeg()」函式將Canvas往順時針旋轉45度,並繪製一個藍色矩形。

rotateDeg(ctx, 45);

接著再進行一次「rotateDeg()」函式將Canvas再往順時針旋轉45度。(此時已旋轉90度)

ctx.translate(20, -100);

到這邊的程式碼就是重點了,理論上如果以基準點為(0,0)的位置來說,目前要設定的相對基準點位置就是位於(200,50)的位置,但是在沒有運用「save/restore」的方式之下,我們必須自己在腦海裡進行一下矩陣轉換,同時根據上一次的基準點位置(100,30)以重設目前基準點位置(20,-100),最後再透過「drawRect(ctx, "green");」繪製出綠色的矩形出來。

範例2 - 採用save/restore

範例2完整的程式碼如下:

<!DOCTYPE html>
<html><head><meta charset="utf-8"></head><body>
<canvas id="a_canvas" width="200" height="150"></canvas>
<script type="text/javascript">
  var canvas = document.getElementById("a_canvas");
  var ctx = canvas.getContext("2d");
  function drawRect(context, color) {
    context.fillStyle = color;
    context.fillRect(0, 0, 100, 30);
  }
  function rotateDeg(context, deg) {
    var rad = deg * Math.PI / 180;
    context.rotate(rad);
  }
  drawRect(ctx, "red");
  ctx.save();            
  ctx.translate(100,30); 
  rotateDeg(ctx, 45);    
  drawRect(ctx, "blue");
  ctx.restore();         
  ctx.translate(200,50); 
  rotateDeg(ctx, 90);    
  drawRect(ctx, "green");
</script>
</body></html>

drawRect(ctx, "red");
ctx.save();            

除了在Canvas上繪製一個紅色的矩形外,這邊還呼叫了「save()」函式,意指為將目前的基準點位置(0,0)狀態「Push」到「Stack」中,以方便待會取回。

ctx.translate(100,30); 
rotateDeg(ctx, 45);    
drawRect(ctx, "blue");

將目前Canvas的基準點位置設為(100,30),同時旋轉45度並繪製上一個藍色矩形。

ctx.restore(); 

這裡呼叫「restore()」函式的重點就是要將剛剛「Push」到「Stack」的Canvas狀態取回,也就是重設基準點位置回到(0,0),並忘掉「save()」和「restore()」之間所設定的Canvas狀態,如:translate()、rotate()。

ctx.translate(200,50); 
rotateDeg(ctx, 90);    
drawRect(ctx, "green");

最後再重設基準點位置為(200,50),並順時針旋轉90度,然後畫上綠色矩形即大功告成,到這邊可以發現端倪了嗎?假設我們不採用「save/restore」函式來輔助的話,我們需要去進行矩陣轉換,而這只是個小範例~ 如果更複雜的圖形那勢必會轉到頭昏眼花... Orz,而透過「save/restore」函式的輔助,不僅讓程式碼的可讀性大大地增加,而且維護上也較為容易些嚕。

參考資源

Understanding save() and restore() for the Canvas Context

2011-11-02 22:14:01

Leave a Comment

Copyright (C) Ching-Shen Chen. All rights reserved.

::: 搜尋 :::

::: 分類 :::

::: Ads :::

::: 最新文章 :::

::: 最新回應 :::

::: 訂閱 :::

Atom feed
Atom Comment