平時我們畫的圖形都是規(guī)規(guī)矩矩的,那么如果我們用線條畫了個抽象派作品,就像下面這圖一樣,童鞋們知道怎么用fill()染色呢?

這里就要用到數(shù)學上的一個方法——非零環(huán)繞原則,來判斷哪塊區(qū)域是里面,哪塊區(qū)域是外面。接下來,我們具體來看下什么是非零環(huán)繞原則。

首先,我們得給圖形確定一條路徑,只要“一筆畫”并且“不走重復路線”就可以了。如圖,標出的是其中的一種路徑方向。我們先假定路徑的正方向為1(其實為-1啥的也都可以,正負方向互為相反數(shù),不是0就行),那么反方向就是其相反數(shù)-1。
然后,我們在子路徑切割的幾塊區(qū)域內的任意一點各取一條方向任意的射線,這里我只取了三個區(qū)域的射線為例,來判斷這三塊區(qū)域是“里面”還是“外面”。
接下來,我們就來判斷了。S1中引出的射線L1,與S1的子路徑的正方向相交,那么我們就給計數(shù)器+1,結果為+1,在外面。
S2中引出的射線L2,與兩條子路徑的正方向相交,計數(shù)器+2,結果為+2,在外面。
S3中引出的射線L3,與兩條子路徑相交,但是其中有一條的反方向,計數(shù)器+1-1,結果為0,在里面。沒錯,只要結果不為0,該射線所在的區(qū)域就在外面。
記得我們之前學過的arc方法嗎?它的最后一個參數(shù)就是判斷是路徑方向的,如果是路徑相反的兩個同心圓在一起,圖上色會有什么神奇的效果呢?

下面我們通過代碼來實現(xiàn)它。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>圓環(huán)</title>
<style>
body { background: url("./images/bg3.jpg") repeat; }
#canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="canvas">
你的瀏覽器居然不支持Canvas?!趕快換一個吧!!
</canvas>
</div>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "#FFF";
context.fillRect(0,0,800,600);
context.shadowColor = "#545454";
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 2;
context.arc(400, 300, 200, 0, Math.PI * 2 ,false);
context.arc(400, 300, 230, 0, Math.PI * 2 ,true);
context.fillStyle = "#00AAAA";
context.fill();
};
</script>
</body>
</html>
運行結果:

結合我們上一節(jié)學到了陰影效果,這個圓環(huán)看上去是不是特別的有立體感?
接下來,我們利用非零環(huán)繞原則和陰影來繪制一個鏤空的剪紙效果。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>鏤空剪紙效果</title>
<style>
body { background: url("./images/bg3.jpg") repeat; }
#canvas { border: 1px solid #aaaaaa; display: block; margin: 50px auto; }
</style>
</head>
<body>
<div id="canvas-warp">
<canvas id="canvas">
你的瀏覽器居然不支持Canvas?!趕快換一個吧!!
</canvas>
</div>
<script>
window.onload = function(){
var canvas = document.getElementById("canvas");
canvas.width = 800;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "#FFF";
context.fillRect(0,0,800,600);
context.beginPath();
context.rect(200,100,400,400);
drawPathRect(context, 250, 150, 300, 150);
drawPathTriangle(context, 345, 350, 420, 450, 270, 450);
context.arc(500, 400, 50, 0, Math.PI * 2, true);
context.closePath();
context.fillStyle = "#058";
context.shadowColor = "gray";
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowBlur = 10;
context.fill();
};
//逆時針繪制矩形
function drawPathRect(cxt, x, y, w, h){
/**
* 這里不能使用beginPath和closePath,
* 不然就不屬于子路徑而是另一個全新的路徑,
* 無法使用非零環(huán)繞原則
*/
cxt.moveTo(x, y);
cxt.lineTo(x, y + h);
cxt.lineTo(x + w, y + h);
cxt.lineTo(x + w, y);
cxt.lineTo(x, y);
}
//逆時針繪制三角形
function drawPathTriangle(cxt, x1, y1, x2, y2, x3, y3){
cxt.moveTo(x1,y1);
cxt.lineTo(x3,y3);
cxt.lineTo(x2,y2);
cxt.lineTo(x1,y1);
}
</script>
</body>
</html>
運行結果:

這里手動繪制矩形的原因是我們想要得到逆時針路徑的矩形,而且API提供的rect()方法繪制是順時針矩形。另外,需要注意的是,這個剪紙是一個圖形,一個路徑。不能在繪制鏤空三角形和繪制鏤空矩形的方法里使用beginPath()和closePath(),不然它們就會是新的路徑、新的圖形,而不是剪紙的子路徑、子圖形,就無法使用非零環(huán)繞原則。
好了,這一節(jié)的內容就到這里,內容相對來說還是比較簡單實用的。下一節(jié)就是Canvas API的最后一節(jié)了,大家已經(jīng)掌握了這么多的繪制方法,是不是躍躍欲試了呢?那么,就揚起手中的筆,繪出自己的藝術家之魂吧~