2012-11-29 61 views
6

使用<canvas>標籤我需要能夠在多邊形中繪製一個孔。帶有HTML5畫布中間的孔的多邊形

現在我有一些非常簡單的使用beginPath(),然後爲每個點做lineTo()。然後填充fill()。

我看不出有什麼辦法讓一個填充的多邊形與一個未填充的中間,但像一個甜甜圈。 我不是做甜甜圈,但它適合這個例子。

有什麼我失蹤? 我寧願不把它填滿,然後不得不重新繪製中間。

+1

你爲什麼不想要一個甜甜圈 ?甜甜圈很棒! 請參考此鏈接繪製形狀:https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Drawing_shapes – jazzytomato

+0

我同意甜甜圈值得一提。這個鏈接:http://www.w3schools.com/tags/ref_canvas.asp也可以是有用的。 – GameAlchemist

+1

只是爲了澄清,我畫了一個複雜的多邊形與數百個點。甜甜圈只是在多邊形中間有一個洞的類比。 – Nick

回答

18

這是我做它的工作:

var ctx = canvas.getContext("2d");  
ctx.beginPath(); 

//polygon1--- usually the outside polygon, must be clockwise 
ctx.moveTo(0, 0); 
ctx.lineTo(200, 0); 
ctx.lineTo(200, 200); 
ctx.lineTo(0, 200); 
ctx.lineTo(0, 0); 
ctx.closePath(); 

//polygon2 --- usually hole,must be counter-clockwise 
ctx.moveTo(10, 10); 
ctx.lineTo(10,100); 
ctx.lineTo(100, 100); 
ctx.lineTo(100, 10); 
ctx.lineTo(10, 10); 
ctx.closePath(); 

// add as many holes as you want 
ctx.fillStyle = "#FF0000"; 
ctx.strokeStyle = "rgba(0.5,0.5,0.5,0.5)"; 
ctx.lineWidth = 1; 
ctx.fill(); 
ctx.stroke(); 

這裏的主要想法是,你只能使用一次beginPath方法;外面的多邊形必須是順時針的,孔必須是逆時針的。

+0

完美,應接受IMO。 –

+0

它工作完美,但我現在想知道有沒有機會按順時針或逆時針順序點。我發現了一些算法,但沒有一個不能用於非凸多邊形。 –

+0

在我看來,對於外部多邊形和反向孔的方向不一定是順時針的 - 它們只需要相反。上下文假定第一個輸入多邊形的方向爲_right_,至少在Chrome中。 –

1

在時鐘方向繪製形狀(例如)。然後你可以增加或減少半徑並逆時針方向。

+0

-1沒有解釋,只發佈一個可能潛在死亡的鏈接是不行的 – Aprillion

+1

解釋是第一句話。 – Richard

+1

感謝您發佈您的答案!請務必仔細閱讀[自助推廣常見問題](http://stackoverflow.com/faq#promotion)。另請注意,每次鏈接到您自己的網站/產品時,您都必須*發佈免責聲明。 –

12

您有2個選擇可以用HTML5畫布繪製孔。

選擇1:
在不同的時鐘方向繪製外部形狀和內部形狀。

外形順時針和內形逆時針。
或順時針外形​​和逆時針內形。

ctx.beginPath(); 
//outer shape, clockwise 
ctx.moveTo(100,20); 
ctx.lineTo(200,200); 
ctx.lineTo(20,200); 
ctx.closePath(); 
//inner shape (hole), counter-clockwise 
ctx.moveTo(100,100); 
ctx.lineTo(70,170); 
ctx.lineTo(140,170); 
ctx.closePath(); 
//fill 
ctx.fillStyle = "#FF0000"; 
ctx.fill(); 

當我們編碼時,檢測形狀繪製方向有點痛苦。

如果需要檢測一系列的點是順時針還是不行,這裏是一個不錯的功能:

function isClockwise(dots){ 
    var sum = 0; 
    for(var i=1, n=dots.length; i<n; i++){ 
     sum += (dots[i][0] - dots[i-1][0]) * (dots[i][1] + dots[i-1][1]); 
    } 
    sum += (dots[0][0] - dots[n-1][0]) * (dots[0][1] + dots[n-1][1]); 
    return sum < 0; 
} 
console.log(isClockwise([[100,20], [200,200], [20,200]])); //true 
console.log(isClockwise([[100,20], [20,200], [200,200]])); //false 

如果你的點是順時針的,但你需要逆時針,.reverse()你點陣列。

var dots = [[100,20], [200,200], [20,200]]; 
dots.reverse(); 

選擇2:
使用 'EVENODD' 補規則,畫出你的形狀在任何方向。

這種方式比選擇1
看到fill() method API簡單得多:

void ctx.fill(); 
    void ctx.fill(fillRule); 
    void ctx.fill(path, fillRule); 

fillRule可以「非零」「EVENODD」
「非零」:在非零繞線規則,這是默認規則。
「evenodd」:偶數的纏繞規則。

enter image description here

1

您可以使用evenodd填充規則:fill('evenodd')

Even-odd rule

// properties 
 
// - outer square 
 
var outerLength = 200; 
 
// - inner length 
 
var innerLength = outerLength/2; 
 

 
// cnavas 
 
var canvas = document.getElementById('canvas'); 
 
var width = canvas.width = document.body.clientWidth; 
 
var height = canvas.height = document.body.clientHeight; 
 
var context = canvas.getContext('2d'); 
 

 
// path 
 
// - outer square 
 
context.rect(
 
    (width - outerLength)/2, 
 
    (height - outerLength)/2, 
 
    outerLength, 
 
    outerLength 
 
); 
 
// - inner square 
 
var x0 = (width - innerLength)/2; 
 
var y0 = (height - innerLength)/2; 
 
context.moveTo(x0, y0); 
 
context.rect(
 
    x0, 
 
    y0, 
 
    innerLength, 
 
    innerLength 
 
); 
 

 
// draw 
 
// - stroke 
 
context.lineWidth = 10; 
 
context.stroke(); 
 
// - fill 
 
context.fillStyle = 'red'; 
 
context.fill('evenodd');
html, 
 
body { 
 
    margin: 0; 
 
    height: 100%; 
 
    overflow: hidden; 
 
}
<canvas id="canvas"><canvas>