Canvas 2D non-zero and parity rules

Posted May 28, 20204 min read

![Even-odd_and_non-zero_winding_fill_rules.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590376096615-486c44d1-f29f-44c1 -83e7-c130c9dc1521.png # align = left & display = inline & height = 1905 & margin =%5Bobject%20Object%5D & name = Even-odd_and_non-zero_winding_fill_rules.png & originHeight = 1905 & originWidth = 2000 & size = 236024 & status = done & style = none_width_ "2000")
The left is a parity wrap, the right is a non-zero wrap

surroundings

2D graphics may use different graphics libraries for different browsers in different systems.

  • chrome uses skia graphics library
  • firefox is using cairo graphics function library

skia and cairo are packages for the backend, so it can be cross-platform. Although the graphics library used by chrome is skia, the underlying graphics library may still be different on different systems, such as the default system:

  • mac os is the core Quartz 2D graphics library
  • The underlying engines of windows xp and below use GDI,GDI +, and after Windows Vista use Direct2D

![image.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590392433286-36800144-a8af-4d6e-a813-52f5b87cb8f5 .png # align = left & display = inline & height = 214 & margin =%5Bobject%20Object%5D & name = image.png & originHeight = 280 & originWidth = 456 & size = 17558 & status = done & style = none & width = 348 "image.png")
Windows Vista

Fill and render in canvas and svg, CanvasRenderingContext2D.fill() is Canvas 2D API According to the current filling style, fill the current or existing path, use odd or non-zero surround Rules **.

![image.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590397435761-afcb9c88-334c-42b7-afb3-c3bc39ce5555 .png # align = left & display = inline & height = 453 & margin =%5Bobject%20Object%5D & name = image.png & originHeight = 461 & originWidth = 384 & size = 47112 & status = done & style = none & width = 377 "image.png")

Even-odd Rule

Parity is any point P in the area surrounded by the path makes a ray outward, if the total number of intersecting edges is odd-numbered, otherwise it is not filled

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

context.strokeStyle = "rgb(0,0,0)";
context.fillStyle = "rgb(250,0,0)"

context.beginPath();
context.moveTo(100, 0);
context.lineTo(100 + Math.cos(Math.PI * 3/10) * 100, 100 + Math.sin(Math.PI * 3/10) * 100);
context.lineTo(100-Math.cos(Math.PI * 1/10) * 100, 100-Math.sin(Math.PI * 1/10) * 100);
context.lineTo(100 + Math.cos(Math.PI * 1/10) * 100, 100-Math.sin(Math.PI * 1/10) * 100);
context.lineTo(100-Math.cos(Math.PI * 3/10) * 100, 100 + Math.sin(Math.PI * 3/10) * 100);
context.lineTo(100, 0);
context.fill('evenodd');
context.stroke();
context.closePath();

![image.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590398083698-341247ff-314a-44d8-a029-744a29e3959d .png # align = left & display = inline & height = 229 & margin =%5Bobject%20Object%5D & name = image.png & originHeight = 458 & originWidth = 490 & size = 85679 & status = done & style = none & width = 245 "image.png")

Nonzero Rule

Non-zero is Any point P in the area surrounded by the path makes a ray outward, the number of surrounds is 0, if the intersecting sides are from left to right, the number of surrounds is subtracted by 1, the number of right to left surrounds is increased by 1, and the number of surrounds is not Zero padding, otherwise no padding.

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

context.strokeStyle = "rgb(0,0,0)";
context.fillStyle = "rgb(250,0,0)"

context.beginPath();
context.moveTo(100, 0);
context.lineTo(100 + Math.cos(Math.PI * 3/10) * 100, 100 + Math.sin(Math.PI * 3/10) * 100);
context.lineTo(100-Math.cos(Math.PI * 1/10) * 100, 100-Math.sin(Math.PI * 1/10) * 100);
context.lineTo(100 + Math.cos(Math.PI * 1/10) * 100, 100-Math.sin(Math.PI * 1/10) * 100);
context.lineTo(100-Math.cos(Math.PI * 3/10) * 100, 100 + Math.sin(Math.PI * 3/10) * 100);
context.lineTo(100, 0);
context.fill('nonzero');
context.stroke();
context.closePath();

![image.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590398124432-2335c271-3462-493f-8dc8-7f6ecf4d2b0c .png # align = left & display = inline & height = 224 & margin =%5Bobject%20Object%5D & name = image.png & originHeight = 448 & originWidth = 458 & size = 85996 & status = done & style = none & width = 229 "image.png")

to sum up

Why are the graphics rendered in the two ways different?

![image.png]( https://i0.wp.com/segmentfault.comhttps://cdn.nlark.com/yuque/0/2020/png/274532/1590399849475-bf2c6023-b23b-4481-9e7a-793625cf55b8 .png # align = left & display = inline & height = 218 & margin =%5Bobject%20Object%5D & name = image.png & originHeight = 436 & originWidth = 442 & size = 122619 & status = done & style = none & width = 221 "image.png")
Because lineTo is clockwise by default, you cannot control the direction like the arc method. When the parity wraps around, the 2 intersecting edges are not filled, and the non-zero surround intersecting 2 edges from left to right are -2, filling