左为奇偶环绕,右为非零环绕
环境
2D 图形不同系统不同浏览器使用图形库可能都不一样。
-
chrome
使用的是skia
图形函数库 -
firefox
使用的是cairo
图形函数库
skia
和 cairo
是对后端(backend)的封装,所以可以跨平台,虽然 chrome
使用的图形库是 skia
,但是在不同系统上底层图形库还是可能不一样,比如默认系统:
- mac os 是核心
Quartz 2D
图形库 - windows xp 及以下版本底层引擎是使用
GDI
、GDI+
,Windows Vista 后使用Direct2D
Windows Vista
在 canvas
和 svg
里面进行填充渲染,CanvasRenderingContext2D.fill()
就是 Canvas 2D API 根据当前填充的样式,填充当前或已经存在的路径,采用 奇偶或非零环绕规则 。
奇偶(Even-odd Rule)
奇偶就是 路径包围的区域任意点 P 向外做一条射线,如果相交的边总数是奇数填充,反之不填充 。
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();
非零(Nonzero Rule)
非零就是 路径包围的区域任意点 P 向外做一条射线,环绕数为 0,如果相交的边是从左向右环绕数减 1,从右向左环绕数加 1,环绕数不为零填充,反之不填充 。
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();
总结
为什么 2 种方式渲染出来的图形不一样?
因为 lineTo
默认按照顺时针,无法像 arc
方法一样控制方向, 奇偶环绕时 2 个相交的边,不填充,非零环绕相交 2 个从左向右的边,是 -2,填充