大家好,我是前端西瓜哥。
这篇文章简单过一下 canvaskit 的高级功能,布尔运算。
用法
canvaskit 支持布尔运算,用法是创建两个 path 对象 path1 和 path2,然后调用 path1 的 op 方法,传入 path2 和布尔类型。
然后 path1 的路径就会更新为布尔运算后的结果。
path1.op(path2, CanvasKit.PathOp.Intersect);
例子
线上完整 demo 地址:
矩形和圆形相交的核心代码:
const rectPath = new CanvasKit.Path().addRect(
CanvasKit.XYWHRect(20, 20, 100, 100),
);
const circlePath = new CanvasKit.Path().addOval(
CanvasKit.XYWHRect(50, 50, 100, 100),
);
// 进行布尔运算
const booleanPath = rectPath.copy(); // 如果不希望改变 rectPath,就克隆一下
booleanPath.op(circlePath, CanvasKit.PathOp.Intersect); // 使用布尔“并集”
console.log(booleanPath.toSVGString());
// 绘制
canvas.drawPath(booleanPath, fillPaint);
canvas.drawPath(rectPath, strokePaint);
canvas.drawPath(circlePath, strokePaint);
我们可以选择布尔类型,它们的枚举值保存在 CanvasKit.PathOp 中,有以下几种:
-
Intersect:交集,A 且 B;
-
Union:联集,A 或 B;
-
XOR:对称差集,只能是 A 或只能是 B(不能同时为 A 和 B),类似异或运算;
-
Difference:相对补集,A,但不能是 B;
-
ReverseDifference:反向的相对补集,B,但不能是 A;
读者可以把线上代码中的 CanvasKit.PathOp.Intersect 替换为其他布尔枚举值,看看效果。
布尔后的 path 数据
另外,我们也是能拿到布尔后的路径数据的。
path.toSVGString()
该方法会返回一个 SVG 的 path 命令字符串。
上面矩形和圆布尔得到路径,发现有很多二阶贝塞尔命令(Q),有点冗余。
M120,54.1742
L120,120
L54.1742,120 Q53.1445,117.641,52.3626,115.188
Q51.5806,112.735,51.0547,110.215 Q50.5287,107.696,50.2644,105.135 Q50,102.574,50,100
Q50,98.7726,50.0602,97.5466 Q50.1205,96.3207,50.2408,95.0991 Q50.3611,93.8776,50.5412,92.6635
Q50.7213,91.4493,50.9607,90.2455 Q51.2002,89.0416,51.4984,87.851
Q51.7967,86.6603,52.153,85.4858 Q52.5093,84.3112,52.9228,83.1555
Q53.3363,81.9998,53.806,80.8658 Q54.2757,79.7318,54.8005,78.6222
Q55.3253,77.5126,55.9039,76.4302 Q56.4825,75.3477,57.1136,74.2949
Q57.7446,73.2421,58.4265,72.2215 Q59.1084,71.2009,59.8396,70.215
Q60.5708,69.2291,61.3495,68.2803 Q62.1281,67.3315,62.9524,66.422
Q63.7767,65.5126,64.6447,64.6447 Q65.5126,63.7767,66.422,62.9524
Q67.3315,62.1281,68.2803,61.3495 Q69.2291,60.5708,70.215,59.8396
Q71.2009,59.1084,72.2215,58.4265 Q73.2421,57.7446,74.2949,57.1136
Q75.3477,56.4825,76.4302,55.9039 Q77.5126,55.3253,78.6222,54.8005
Q79.7318,54.2757,80.8658,53.806 Q81.9998,53.3363,83.1555,52.9228
Q84.3112,52.5093,85.4858,52.153 Q86.6603,51.7967,87.851,51.4984
Q89.0416,51.2002,90.2455,50.9607 Q91.4493,50.7213,92.6635,50.5412
Q93.8776,50.3611,95.0991,50.2408 Q96.3207,50.1205,97.5466,50.0602 Q98.7726,50,100,50
Q102.574,50,105.135,50.2644 Q107.696,50.5287,110.215,51.0547 Q112.735,51.5806,115.188,52.3626 Q117.641,53.1445,120,54.1742
Z
使用的路径可视化工具:
对此我们可以学学 Figma,将圆转换为 4 段 三阶贝塞尔曲线来拟合。
// 圆改为用 4 条三阶贝塞尔曲线来拟合
const circlePath = new CanvasKit.Path()
.moveTo(150, 100)
.cubicTo(150, 127.614, 127.614, 150, 100, 150)
.cubicTo(72.386, 150, 50, 127.614, 50, 100)
.cubicTo(50, 72.386, 72.386, 50, 100, 50)
.cubicTo(127.614, 50, 150, 72.386, 150, 100)
.close();
然后再进行布尔运算,数据就清爽了。
M 120,54.1605
L 120,120
L 54.1605,120
C 51.4845,113.875,50,107.111,50,100
C 50,72.386,72.386,50,100,50
C 107.111,50,113.875,51.4845,120,54.1605
Z
有些设计师认为 Figma 的圆不够圆。这么看来可能是因为是三阶段贝塞尔曲线拟合出的圆,所以和真正的圆会有一点点非常微小的偏差,不过一般来说看不出来吧。
结尾
我是前端西瓜哥,关注我,学习更多前端图形知识。
相关阅读,