Polygon with a hole in the middle with HTML5 canvas

Using the <canvas> , I should be able to draw a hole in the polygon.

Right now I have something very simple using beginPath (), and then lineTo () is used for each point. Then it is filled using fill ().

I see no way to have a filled polygon with an unfilled medium, though, like a donut. I don’t make a donut, but it is suitable for this example.

Is there something I am missing? I would rather not draw it fully filled, and then redraw the middle.

+6
source share
4 answers

Here is what I did this:

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

The basic idea here is that you can only use startPath once; the outer polygon should be clockwise, and the holes should be counterclockwise.

+18
source

You have 2 options for drawing holes with an HTML5 canvas.

Choice 1:
Draw the outer shape and inner shape in different measures.

The outer form is clockwise and the inner form is counterclockwise.
Or the outer form is clockwise and the inner form is counterclockwise.

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

It’s a little pain to determine the direction in which the form is drawn when coding.

If you need to determine if there is a series of dots clockwise or not, here is a nice function:

 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 

If your points are clockwise, but you need counterclockwise, .reverse () is your array of points.

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

Choice 2:
Use the 'evenodd' fill rule, draw your shapes in any direction.
This method is much simpler than choice 1.
see the fill () method API :

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

fillRule can be nonzero or evenodd
nonzero: non-zero winding rule, which is the default standard.
"evenodd": even winding rule.

 ctx.beginPath(); //outer shape, any direction, this sample is clockwise ctx.moveTo(100,20); ctx.lineTo(200,200); ctx.lineTo(20,200); ctx.closePath(); //inner shape (hole), any direction, this sample is clockwise ctx.moveTo(100,100); ctx.lineTo(140,170); ctx.lineTo(70,170); ctx.closePath(); //fill ctx.fillStyle = "#FF0000"; ctx.mozFillRule = 'evenodd'; //for old firefox 1~30 ctx.fill('evenodd'); //for firefox 31+, IE 11+, chrome 

enter image description here

+12
source

Draw your figure in the clockwise direction (for example). Then you can increase or decrease the radius and go counterclockwise.

+1
source

You can use the evenodd fill rule: fill('evenodd')

Odd-even 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> 
+1
source

All Articles