Hi,
I am playing around with cetz and trying to create a custom element that behave like native ones.
I first tried a naive approach with this code (I am currently focusing on being able to use the anchors facilities) :
#import "@preview/cetz:0.4.2"
#set page(width: auto, height: auto, margin: .5cm)
#cetz.canvas({
import cetz.draw: *
grid((-10, -10), (10, 10), stroke: gray + 0.5pt)
let head = (pos, anchor: none, radius: 4, name: none) => group(name: name, {
let r = radius / 3
set-origin(pos)
cetz.draw.anchor("left-eye", (r, -r))
cetz.draw.anchor("right-eye", (-r, -r))
cetz.draw.anchor("mouth", (0, r))
if anchor != none { set-origin(anchor) }
circle((0, 0), radius: radius)
circle((-r, r), radius: r / 2)
circle((r, r), radius: r / 2)
line((-r, -r), (r, -r))
cetz.draw.anchor("left-eye", (-r, r))
cetz.draw.anchor("right-eye", (r, r))
cetz.draw.anchor("mouth", (0, -r))
})
circle((-4, 4), radius: .2, fill: green, name: "green")
head("green")
circle((-2, -4), radius: .2, fill: red, name: "red")
head("red", anchor: "left-eye")
head((5, 5), name: "a")
circle("a.left-eye", radius: .2, fill: blue)
})
But obviously, this is not the right approach…
I took a look at cetz code and tried to copy the def of circle
from shape.typ to create my head
element.
#import "@preview/cetz:0.4.2"
#set page(width: auto, height: auto, margin: .5cm)
#let head(..points-style, name: none, anchor: none) = {
import cetz.draw: *
//import cetz.coordinate: *
let style = points-style.named()
let points = points-style.pos()
assert(points.len() in (1, 2),
message: "circle expects one or two points, got " + repr(points))
assert(points.len() != 2 or "radius" not in style,
message: "unexpected radius for circle constructed by two points")
(ctx => {
let (center, outer) = if points.len() == 1 {
(points.at(0), none)
} else {
points
}
let (ctx, center) = cetz.coordinate.resolve(ctx, center)
let style = cetz.styles.resolve(ctx.style, merge: style, root: "circle")
// If we got two points, use the second one to calculate
// the radius.
let (rx, ry) = if outer != none {
(ctx, outer) = coordinate.resolve(ctx, outer, update: false)
(vector.dist(center, outer),) * 2
} else {
cetz.util.resolve-radius(style.radius).map(cetz.util.resolve-number.with(ctx))
}
let (cx, cy, cz) = center
let drawables = cetz.drawable.ellipse(
cx, cy, cz,
rx, ry,
fill: style.fill,
stroke: style.stroke
)
let (transform, anchors) = anchor_.setup(
(_) => center,
("center",),
default: "center",
name: name,
offset-anchor: anchor,
transform: ctx.transform,
border-anchors: true,
path-anchors: true,
radii: (rx*2, ry*2),
path: drawables,
)
return (
ctx: ctx,
name: name,
anchors: anchors,
drawables: drawable.apply-transform(transform, drawables),
)
},)
}
#cetz.canvas({
import cetz.draw: *
grid((-10, -10), (10, 10), stroke: gray + 0.5pt)
head((0,0))
})
I wasn’t even able to compile it since cetz does not export functions from anchor (Anchor | CeTZ Documentation), at least, I couldn’t find it. So I have the error unknown variable: anchor_
.
So, my question is, does anyone has an example of how to create a custom element ?