canvaskit-wasm 0.39
build 2026-04-29
PathOp
The boolean operation passed to CK.Path.MakeFromOp(a, b, op). Combines two paths into one, treating each as a 2D region. Output is a fresh Path made of cubic Bezier segments wherever Skia rounds intersection corners.
const op = controls.select(
'op', ['Union', 'Intersect', 'Difference', 'ReverseDifference', 'XOR'], 'Intersect'
);
const a = new CK.Path(); a.addCircle(165, 130, 70);
const b = new CK.Path(); b.addCircle(255, 130, 70);
const ghost = new CK.Paint();
ghost.setStyle(CK.PaintStyle.Stroke);
ghost.setColor(CK.Color(160, 160, 160, 0.6));
const fill = new CK.Paint();
fill.setColor(CK.Color(60, 160, 90, 0.4));
fill.setAntiAlias(true);
const edge = new CK.Paint();
edge.setStyle(CK.PaintStyle.Stroke);
edge.setStrokeWidth(2);
edge.setColor(CK.Color(60, 160, 90, 1));
edge.setAntiAlias(true);
loop(() => {
canvas.clear(CK.WHITE);
canvas.drawPath(a, ghost);
canvas.drawPath(b, ghost);
const out = CK.Path.MakeFromOp(a, b, CK.PathOp[op()]);
if (out) {
canvas.drawPath(out, fill);
canvas.drawPath(out, edge);
out.delete();
}
surface.flush();
});
Here is another example where you could see points of the result path
const op = controls.select(
'mode', ['shapes', 'union', 'intersect', 'difference', 'xor'], 'intersect'
);
const star = new CK.Path();
makeStar(star, 200, 130, 80, 35, 5);
const planeSvg = "M16.63,105.75c0.01-4.03,2.3-7.97,6.03-12.38L1.09,79.73c-1.36-0.59-1.33-1.42-0.54-2.4l4.57-3.9c0.83-0.51,1.71-0.73,2.66-0.47l26.62,4.5l22.18-24.02L4.8,18.41c-1.31-0.77-1.42-1.64-0.07-2.65l7.47-5.96l67.5,18.97L99.64,7.45c6.69-5.79,13.19-8.38,18.18-7.15c2.75,0.68,3.72,1.5,4.57,4.08c1.65,5.06-0.91,11.86-6.96,18.86L94.11,43.18l18.97,67.5l-5.96,7.47c-1.01,1.34-1.88,1.23-2.65-0.07L69.43,66.31L45.41,88.48l4.5,26.62c0.26,0.94,0.05,1.82-0.47,2.66l-3.9,4.57c-0.97,0.79-1.81,0.82-2.4-0.54l-13.64-21.57c-4.43,3.74-8.37,6.03-12.42,6.03C16.71,106.24,16.63,106.11,16.63,105.75L16.63,105.75z";
const planeBase = CK.Path.MakeFromSVGString(planeSvg);
const pb = planeBase.computeTightBounds();
planeBase.offset(-(pb[0] + pb[2]) / 2, -(pb[1] + pb[3]) / 2);
const k = 0.9, c45 = cos(PI / 4), s45 = sin(PI / 4);
planeBase.transform([k * c45, -k * s45, 0, k * s45, k * c45, 0]);
const plane = new CK.Path();
const ghost = new CK.Paint();
ghost.setStyle(CK.PaintStyle.Stroke);
ghost.setColor(CK.Color(160, 160, 160, 0.6));
const fill = new CK.Paint();
fill.setColor(CK.Color(60, 160, 90, 0.3));
fill.setAntiAlias(true);
const edge = new CK.Paint();
edge.setStyle(CK.PaintStyle.Stroke);
edge.setStrokeWidth(2);
edge.setColor(CK.Color(60, 160, 90, 1));
edge.setAntiAlias(true);
const PATH_OPS = {
union: CK.PathOp.Union,
intersect: CK.PathOp.Intersect,
difference: CK.PathOp.Difference,
xor: CK.PathOp.XOR,
};
let lastOp = 'intersect';
loop(() => {
plane.reset();
plane.addPath(planeBase);
if(op() !== lastOp){
lastOp = op();
mouse.x = 200; mouse.y = 130;
}
plane.offset(mouse.x || 200, mouse.y || 130);
canvas.clear(CK.WHITE);
canvas.drawPath(star, ghost);
canvas.drawPath(plane, ghost);
if (op() === 'shapes') {
canvas.drawAnchors(star);
canvas.drawAnchors(plane);
} else {
const out = CK.Path.MakeFromOp(plane, star, PATH_OPS[op()]);
canvas.drawPath(out, fill); canvas.drawPath(out, edge);
canvas.drawTangents(out);
out.delete();
}
surface.flush();
});
function makeStar(p, cx, cy, R, r, n) {
for (let i = 0; i < n * 2; i++) {
const a = -PI / 2 + i * PI / n;
const rr = i % 2 === 0 ? R : r;
if (i === 0) p.moveTo(cx + cos(a) * rr, cy + sin(a) * rr);
else p.lineTo(cx + cos(a) * rr, cy + sin(a) * rr);
}
p.close();
}
All values
| Value | Result | Notes |
|---|---|---|
Difference | A − B | Everything in a that's not in b. |
Intersect | A ∩ B | Only the overlap. |
Union | A ∪ B | Everything in either path. |
XOR | A ⊕ B | Everything in exactly one of the two — overlap is excluded. |
ReverseDifference | B − A | Everything in b that's not in a. Same as Difference with the inputs swapped. |
See also
Path.MakeFromOp— the static factory that consumes this enum.Path— what comes out the other side, ready fordrawPath.- Paths and cubics — why boolean output uses cubics (planned).