Skip to main content

Command Palette

Search for a command to run...

path 的填充与镂空 - 关于 fill-rule

Updated
•1 min read•View as Markdown
path 的填充与镂空 - 关于 fill-rule

参考前文:

https://hashnode.com/post/clojx8gwy000509l2gw6v53oy

前文提到过 path 实现镂空效果的办法,我遗漏了一种情况,就以这种情况作为问题来开头:

M 0 0 h 100 v 50 h -48 L 50 55 L 48 50 h -48 v -50 Z
M 10 10 h 10 v 10 h -10 v -10 z

这是一份 path 参数,画着一大一小两个矩形,但画出来的效果并不是镂空的,小矩形被大矩形遮盖,变成了“填充”的效果:

那么填充和镂空究竟是如何判断的呢?为什么两个类似的 path 显示的效果相反呢?这个问题其实关系到 fill-rule 属性。

fill-rule 是一个表现属性,它定义了用来确定一个多边形内部区域的算法。

MDN 说他是一个确定内部区域的算法,他主要有两个值,nonzero 和 evenodd,这个内部就是字面意思,同理还有外部。

path 会把内部当成是自己的一部分,而外部则是自己所不包含的区域(外部不会响应事件),在填充颜色的时候,内部会被上色,而外部不会,所以前一篇文章中的镂空效果,实际上是中间的矩形区域被当成了外部。

那为什么前文中提到的的两个矩形都属于内部呢?接下来看看 fill-rule 的两个取值:

nonzero

这个值确定了某点属于该形状的“内部”还是“外部”:从该点向任意方向的无限远处绘制射线,然后检测形状与射线相交的位置。从 0 开始统计,路径上每一条从左到右(顺时针)跨过射线的线段都会让结果加 1,每条从右向左(逆时针)跨过射线的线段都会让结果减 1。当统计结束后,如果结果为 0,则点在外部;如果结果不为 0,则点在内部。

MDN 讲的很好,但我没看懂,我查阅资料后发现这个其实很好理解。

首先画两个重叠的矩形,大小矩形都按顺时针方向绘制:

M 0 0 h 50 v 50 h -50 z
M 10 10 h 20 v 20 h -20 z

大概是这样,现在要判断蓝色区域是内部还是外部,先在里面随便取一个原点,然后向任意方向发出射线:

射线与两个边均有交点,沿着路径的绘制方向和射线的方向,可以看到都是逆时针的,分数是 -2,不为 0,所以蓝色区域是内部。

那么换一种场景,大小矩形一个按逆时针绘制,另一个按顺时针绘制,还是用原来的射线法,计算出分数为 0,所以蓝色区域是外部:

因为他是外部,所以不算 path 的一部分,上色时就会镂空。

而 fill-rule 的默认取值就是 nonzero,所以在前一篇文章中,相似的 path 导致内部镂空效果不一样的原因就是这个。

由于两个图形叠加的情况太简单了,所以在这个例子中可以直接得到结论“外部和内部图形绘制方向不一样的时候,内部是镂空的,反之是填充的”。

evenodd

这种方式也是计分制,但计分的规则有些不同,还是先放 MDN 的说明:

这个值用确定了某点属于该形状的“内部”还是“外部”:从该点向任意方向无限远处绘制射线,并统计这个形状所有的路径段中,与射线相交的路径段的数量。如果有奇数个路径段与射线相交,则点在内部;如果有偶数个,则点在外部。

这个说明就很简单了,说白了就是看交点的数量,奇数就属于内部,偶数就属于外部。

如图,有两个交点,那么蓝色区域就是外部,可以看到无关路径绘制的方向。

More from this blog

12 月装机行动记录

(Banner 图文无关) 这几天买了新的装备回来升级配置,除了显卡和散热器,其他都更新了,这两个不更新的原因是太贵了。 由于我不太懂选配置,所以还是让朋友给推荐,我说我的预算在 5000 左右,他就给我转了一个整机,配置大概是这样的: CPU:AMD 9700X 主板:微星 B650M GAMING PLUS WIFI 或者 微星 B650M GAMING WIFI 显卡:木有 内存:英睿达/宇瞻 DDR5 6000 32G 硬盘:1T NVMe PCIe4 SSD 读速 3500M...

Dec 7, 20241 min read
12 月装机行动记录

Homekit + cozylife 插座连接 HA

近期在淘宝上买了个 Homekit + cozylife 的插座,就这种: 一开始只通过 iOS 访问,就是只连接 Homekit,长按开关重置插座,iOS 一扫码就连上了,后来我嫌在外面访问不了,又不想掏钱买苹果的 HomePod,于是就装上了 Home Assistant,打算让设备们都连上 HA,这样就不用交苹果税了。 连接方式还是通过 Homekit,一般来说支持 Homekit 设备都能这样连接,先连上 iOS,然后在 Home App 中移除设备,这时候就能在 HA 中找到设备了:...

Nov 30, 20241 min read
Homekit + cozylife 插座连接 HA

找到了一台祖传的 Ccd 相机

开个玩笑,这台相机其实是我们家在 05 年的时候买的,发票都还在呢,当时花了 4000 块钱!搁现在我都受不了,更别说当年了,看到价格我都震惊了。 相机的型号是索尼的 Cybershot DSC-N1,属于小红书时尚单品 CCD 相机,由于一直放在包装盒里,现在还有 99 新呢。 机子还是正常的,能开机,能拍照,其中一个问题是日期,这款没有 WiFi 功能,所以时间只能保存在本地,不知道是不是 BUG,每次开机都让我重新设置,默认就定在 2005 年 1 月 1 日。 第二个问题是电池,电池应该...

Nov 28, 20241 min read
找到了一台祖传的 Ccd 相机

记录和 ffmpeg 与 LLM 搏斗的两天

要做的 最近在写一个制作视频的功能,就是把 N 个视频合并,然后把对应的 N 张图片,在视频开始的前 5 秒叠加显示出来。 第一口 - diffusion studio 本来我用的是 diffusion studio,这是一个 JS 库,但这玩意性能太差了,因为他要把视频每一帧都读到 canvas 里,数据一多页面就卡住了(为啥要折腾 DOM 呢?) 而且他的 API 十分不好用,作为浏览器脚本你无法读本地数据也就算了,你起码给一个接受纯数据的参数吧,比如 HTML 类型接受源代码,Image ...

Nov 16, 20242 min read
记录和 ffmpeg 与 LLM 搏斗的两天
V

void mian

39 posts