HTML5- Canvas入門(七)


這是本系列的最后一篇入門文章,主要是對剩余的未說明的canvas方法來逐個介紹。

首先,如果你是一名擅長矢量設計的設計師,對Illustrator或者Fireworks很熟悉的話,那你肯定知道它們有一個很強大的矢量混合處理功能,可以對多個矢量路徑進行“合並”、“拆分”、“結合”、“相交”等系列操作。 如下圖,在Fireworks中有三個矢量路徑,我先把灰色的圓形和粉紅色的矩形進行了“結合路徑”的處理,接着又把結合后的路徑跟綠色的星形矢量進行了“合並路徑”操作:

在canvas中也有實現同樣功能的屬性—— globalCompositeOperation,利用它,可以實現對畫布上已有的圖像(暫稱為“目標圖像”)和新繪制的圖像(暫成為“源圖像”)來執行相關的混合處理。

globalCompositeOperation的可取值見下表:

描述
source-over 默認。在目標圖像上顯示源圖像。
source-atop 在目標圖像頂部顯示源圖像。源圖像位於目標圖像之外的部分是不可見的。
source-in 在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
source-out 在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
destination-over 在源圖像上方顯示目標圖像。
destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
destination-in 在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
destination-out 在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
lighter 顯示源圖像 + 目標圖像。
copy 顯示源圖像。忽略目標圖像。
xor 使用異或操作,對源圖像與目標圖像進行結合處理。

我們繪制一個藍色的圓形和一個粉紅色的矩形,對它們進行類似上圖“結合路徑”(xor)的處理:

<canvas id="myCanvas" width="300" height="200" style="border:solid 1px #CCC;">
您的瀏覽器不支持canvas,建議使用最新版的Chrome
</canvas>

<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); 
ctx.arc( 80, 80, 40, 0, 2*Math.PI);
ctx.fillStyle = "#4DA6FF";
ctx.fill();
ctx.fillStyle = "#FF7373";
ctx.globalCompositeOperation="xor";  //異或結合處理
ctx.fillRect(95,50,100,90);
</script>

效果如下:

各globalCompositeOperation 屬性值的最終效果可以參考下圖(藍色矩形為目標圖像,紅色圓形為后續新繪制的源圖像):

接着介紹 isPointInPath() 方法,它接受一個指定點的坐標值作為參數,可判斷該指定點是否位於當前路徑內,並返回對應的Boolean值。
我們來繪制一個矩形,然后判斷點(115, 70)是否位於該矩形路徑內部,如果是,則填充該矩形,否則alert出相關信息:

<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(95,50,100,90);
if (ctx.isPointInPath(115,70)){  //判斷點(115,70)是否位於當前路徑內
    ctx.fillStyle = "#FF7373";
    ctx.fill();
}else{
    alert("不在矩形路徑內");
}
</script>

由於該點是位於矩形路徑上的,故成功繪制矩形,而不會彈窗:

 我們常規使用canvas繪制多個圖片的時候,總有一些會重復使用到的狀態,比如我們先繪制了一個“傾斜20度、填充顏色為紅色”的矩形,接着繪制了一個“不傾斜、填充顏色為藍色”的矩形。如果后面我們又要重復繪制一個“傾斜20度、填充顏色為紅色”的矩形,又得重新設置畫布的setTransform和fillStyle值,自然是挺煩人的事情。
canvas的 save() restore() 方法便能為我們處理這個問題——使用 .save() 方法能為我們保存當前畫布的狀態,使用 .restore() 方法可以把當前畫布狀態返回到上一次保存的狀態,有點類似於我們玩游戲過程中存檔和讀檔的功能。
我們先說說canvas的“狀態”,它指的是像我們上面提到的“傾斜(變形)、填充”這樣的配置,是當前所有樣式和變形的一個快照。我們可以保存和讀取到的狀態包括:

當前的 transformation matrix;
當前的 clipping region;
當前的屬性值:fillStyle, font, globalAlpha,
globalCompositeOperation, lineCap, lineJoin,
lineWidth, miterLimit, shadowBlur, shadowColor,
shadowOffsetX, shadowOffsetY, strokeStyle, textAlign,
textBaseline

canvas的狀態是以棧(stack)的方式保存的,遵循先進后出(FILO)原則。每一次調用 save 方法,當前的狀態就會被推入棧中保存起來;當調用 restore 方法時,最新入棧的狀態則被推出使用。
我們來一個簡單的例子:

<canvas id="myCanvas" width="150" height="150" style="border:solid 1px #CCC;">
您的瀏覽器不支持canvas,建議使用最新版的Chrome
</canvas>

<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(20,20,100,100);
ctx.save();  //保存狀態(fillStyle = "green")
ctx.fillStyle = "red";
ctx.fillRect(40,40,60,60);
ctx.restore();  //讀取上次保存的狀態(fillStyle = "green")
ctx.fillRect(60,60,20,20);   //填充了綠色的矩形而非紅色的
</script>

效果如下:

上面的例子很好理解,不過為了了解“狀態入棧出棧”的情況,我們把上面例子改造一下:

<canvas id="myCanvas" width="150" height="150" style="border:solid 1px #CCC;">
您的瀏覽器不支持canvas,建議使用最新版的Chrome
</canvas>

<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "yellow";  //注意這里多了一行狀態定義
ctx.save();    //注意這里多了一行狀態保存
ctx.fillStyle = "green";
ctx.fillRect(20,20,100,100);
ctx.save();
ctx.fillStyle = "red";
ctx.fillRect(40,40,60,60);
ctx.restore();   //推出最后一個入棧的狀態(fillStyle = "green")
ctx.restore();   //再次推出最后一個入棧的狀態(fillStyle = "yellow"),注意green已經在上次restore推出了,故這次取到的是yellow
ctx.fillRect(60,60,20,20);  //填充黃色的矩形
</script>

就像注釋說明的那樣,最終繪制的小矩形是黃色而非綠色:

最后介紹的是 toDataURL() 方法,它能把當前畫布的內容轉換為data類型的URL格式。 等等,“data類型的URL格式”又是什么來的? 有時候我們會在某些頁面(比如github404頁面)看到這樣的圖片:

其src對應的是一串“data:image/png;base64....”的data類型URL格式,返回的base64圖片數據流,可以減少對服務器的圖片請求(當然缺點是無法緩存在客戶端)。這種格式這就是我們上面提到的東西。 那么 toDataURL() 方法的好處就顯而易見了——我們可以把當前畫布內容轉換為一張圖片。

toDataURL() 方法直接作用於canvas對象,而非context2D對象,其格式為:

url = canvas.toDataURL( [ type, ... ] )

參數type表示返回文件的MINE類型,若未指定type,則默認返回的格式必須為PNG格式。如果canvas沒有任何像素,則返回值為:“data:,”,這是最短的data:URL,在text/plain資源中表現為空字符串。
type的值可以在image/png,image/jpeg,image/svg+xml 等MIME類型中選擇。如果是image/jpeg,可以有第二個參數,如果第二個參數的值在0-1之間,則表示JPEG的質量等級,否則使用瀏覽器內置默認質量等級。

我們來個小例子:

<canvas id="myCanvas" width="150" height="150" style="border:solid 1px #CCC;"></canvas>

<button onClick="openImg()">點我查看圖片</button>

<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(20,20,100,100);
ctx.save();
ctx.fillStyle = "red";
ctx.fillRect(40,40,60,60);
ctx.restore(); 
ctx.fillRect(60,60,20,20); 

function openImg(){
    var image = c.toDataURL("image/png"),  //注意toDataURL是canvas對象方法,而不是context2D的屬性
         w  = window.open('about:blank'); 
    w.document.write("<img src='"+image+"' />"); 
}
</script>

點擊“點我查看圖片”的按鈕后會彈出一個新頁面,上面有我們生成的base64編碼形式的圖片(跟canvas上繪制的內容一致):

但由於該圖片是不存在於任何文件目錄上的,自然也無法直接下載該(帶后綴名的)文件,如果想要地道地生成一張圖片供用戶下載,則需要后端配合了(可以參考這里)。
另外有一點要注意的,也就是我們在第五章提到的,如果在canvas中繪制了非本地的圖片,從安全性考慮將無法對其進行讀操作,這種情況下如果執行toDataURL自然也會報錯。不過如果資源開啟了CORS,則有辦法避開同源策略的阻攔(可以參考這里)。

自此,canvas的api我們基本都遍歷了一遍,希望能讓來此學習的朋友有所收獲,共勉~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM