這里就要用到數(shù)學(xué)上的一個方法——非零環(huán)繞原則,來判斷哪塊區(qū)域是里面,哪塊區(qū)域是外面。接下來,我們具體來看下什么是非零環(huán)繞原則。
首先,我們得給圖形確定一條路徑,只要“一筆畫”并且“不走重復(fù)路線”就可以了。如圖,標出的是其中的一種路徑方向。我們先假定路徑的正方向為1(其實為-1啥的也都可以,正負方向互為相反數(shù),不是0就行),那么反方向就是其相反數(shù)-1。
然后,我們在子路徑切割的幾塊區(qū)域內(nèi)的任意一點各取一條方向任意的射線,這里我只取了三個區(qū)域的射線為例,來判斷這三塊區(qū)域是“里面”還是“外面”。
接下來,我們就來判斷了。S1中引出的射線L1,與S1的子路徑的正方向相交,那么我們就給計數(shù)器+1,結(jié)果為+1,在外面。
S2中引出的射線L2,與兩條子路徑的正方向相交,計數(shù)器+2,結(jié)果為+2,在外面。
S3中引出的射線L3,與兩條子路徑相交,但是其中有一條的反方向,計數(shù)器+1-1,結(jié)果為0,在里面。沒錯,只要結(jié)果不為0,該射線所在的區(qū)域就在外面。
JavaScript Code復(fù)制內(nèi)容到剪貼板
- <!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>
JavaScript Code復(fù)制內(nèi)容到剪貼板
- <!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){
-
-
-
-
-
- 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)繞原則。