2012-11-29 12 views
6

Za pomocą znacznika <canvas> potrzebuję móc narysować otwór w wielokącie.Wielokąt z otworem pośrodku z płótnem HTML5

W tej chwili mam coś bardzo prostego, który używa metody beginPath(), a następnie robi lineTo() dla każdego punktu. Następnie wypełnia się wypełnieniem().

Nie widzę żadnego sposobu na wypełnienie wielokąta nie wypełnionym środkiem, jak na przykład pączek. Nie robię pączka, ale nadaje się do tego przykładu.

Czy jest coś, czego mi brakuje? Wolałbym nie rysować go w pełni wypełniony, a następnie trzeba przerysować środek.

+1

Dlaczego nie chcesz zrobić pączek ? Pączki są świetne! odsyłamy do tego linku, aby narysować kształty: https://developer.mozilla.org/en-US/docs/Canvas_tutorial/Drawing_shapes – jazzytomato

+0

Zgadzam się z tym, że pączki warte są remisu. Ten link: http://www.w3schools.com/tags/ref_canvas.asp też może być przydatny. – GameAlchemist

+1

Dla jasności rysuję skomplikowany wielokąt z setkami punktów. Pączek to tylko analogia do dziury w środku wielokąta. – Nick

Odpowiedz

18

To co zrobiłem to działa:

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(); 

Główną ideą jest tutaj można użyć tylko raz beginPath; wielokąt zewnętrzny musi być zgodny z ruchem wskazówek zegara, a otwory muszą być przeciwne do ruchu wskazówek zegara.

+0

Doskonały, powinien być zaakceptowany przez IMO. –

+0

Działa perfekcyjnie, ale teraz zastanawiam się, czy istnieje możliwość zamówienia punktów w kierunku zgodnym lub przeciwnym do ruchu wskazówek zegara. Znalazłem kilka algorytmów, ale żaden z nich nie działa z nie wypukłymi wielokątami. –

+0

Wydaje mi się, że orientacje nie muszą być CW dla zewnętrznego poli i CCW dla otworu - po prostu muszą być przeciwne. Kontekst zakłada orientację pierwszego wielokąta wejściowego jako _right_ jeden, przynajmniej w Chrome. –

1

Narysuj swój kształt w kierunku zgodnym z ruchem wskazówek zegara (na przykład). Następnie można zwiększyć lub zmniejszyć promień i przejść w kierunku przeciwnym do ruchu wskazówek zegara.

+0

-1 bez wyjaśnienia, TYLKO link, który może potencjalnie stać się martwy, nie jest prawidłowy – Aprillion

+1

Wyjaśnienie to pierwsze zdanie. – Richard

+1

Dziękujemy za zamieszczenie odpowiedzi! Pamiętaj, aby uważnie przeczytać [FAQ na temat autopromocji] (http://stackoverflow.com/faq#promotion). Należy również pamiętać, że * wymagane * jest to, że publikujesz zrzeczenie się za każdym razem, gdy łączysz się z własną witryną/produktem. –

12

Masz 2 opcje do rysowania otworów z płótna HTML5.

Wybór 1: Narysuj kształt zewnętrzny i kształt wewnętrzny w różnych kierunkach.

Kształt zewnętrzny zgodny z ruchem wskazówek zegara i wewnętrzny.
Lub zewnętrzny kształt zgodnie z ruchem wskazówek zegara i wewnętrzny przeciwnie do ruchu wskazówek zegara.

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(); 

To trochę bólu, aby wykryć kierunek rysowania kształtu, kiedy kodujemy.

Jeśli trzeba wykryć, czy seria kropek jest w prawo, czy nie, tutaj jest dobrym funkcja:

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 

Jeśli kropki jest do ruchu wskazówek zegara, ale trzeba w lewo, .reverse() twoje kropki szyk.

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

Wybór 2:
Użyj 'evenodd' wypełnić regułę, rysować swoje kształty w dowolnym kierunku.

Ten sposób jest o wiele prostsze niż wybór 1.
zobaczyć fill() method API:

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

fillRule może być "niezerowe" lub "evenodd"
"niezerowe": Niezasychające zasada zerowania uzwojenia, która jest regułą domyślną.
"evenodd": reguła "parzyste".

enter image description here

1

Można użyć evenodd wypełnienia zasadę: 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>