CeTZ Integration

Fletcher aims to be compatible with CeTZ, in the sense that you can use as little or as much of fletcher’s features with CeTZ as you want, and vice versa. Under the hood, fletcher builds upon CeTZ by defining:

Drawing in a CeTZ canvas

Instead of using diagram(), you can place nodes and edges directly inside a CeTZ canvas. If you still want to use tabular layouts like in diagram(), you can wrap the objects in a flexigrid(). For example, the following are equivalent:

Using diagram()Using cetz.canvas()
#diagram(
  node-fill: teal,
  edge-stroke-thickness: 1pt,
  node((0,0), [Hello]),
  edge("->"),
  node((2,1), [There]),
)
#cetz.canvas({
  import cetz.draw: *
  set-style(node: (fill: teal),
            edge: (stroke: 1pt))
  fletcher.flexigrid({
    node((0,0), [Hello])
    edge("->")
    node((2,1), [There])
  })
})

Drawing inside a CeTZ canvas is encouraged when your diagram does not have a natural table-like structure or is very complex. However, some features only work inside diagram() or flexigrid() (for example, in a cetz.canvas() edges cannot snap to nodes declared later).

Normal CeTZ objects may be placed in a flexigrid(), but must opt-in to use 𝑢𝑣 coordinates with (uv: coord), while nodes and edges use 𝑢𝑣 coordinates by default (you can use (xy: coord) to opt-out). Nodes and edges can be given names and participate in CeTZ’s anchoring system.

Applying edge effects to CeTZ paths

You can wrap a CeTZ path in edge() to apply edge effects to it (see Wrapping CeTZ paths). Using edge() in this way is a convenient wrapper to the path modification functions offered by fletcher, which includes path-effect() for applying corner rounding (for edge.corner-radius) and offsetting (for edge.extrude) to CeTZ paths, and apply-edge-effects() for placing marks and labels.

#cetz.canvas({
  import cetz.draw: *

  let path = line((0,0), (1,0), (2,1), (2,0), (3,0), stroke: 0.5pt)
  path // plain cetz path

  translate(y: -2)

  edge(path, ")==>", text(blue)[_effects_], stroke: 1pt + blue)
})

Snapping edges to CeTZ objects

You can use edge() to enable path snapping. You can make edges snap to nodes or plain CeTZ objects using the edge.snap-to option and providing a name. You can also make plain CeTZ paths snap to objects by wrapping them in edge().

#cetz.canvas({
  import cetz.draw: *

  // plain cetz objects with names
  line((0,0), (1,1), (2,0), (1,-1), close: true, name: "l")
  circle((3,0), radius: 0.3, name: "c")

  set-style(edge: (stroke: 1pt + eastern)) // styles applied edge(..)

  // fletcher edge snapping to cetz objects
  edge((1,0), "-->", (3,0), bend: -40deg, snap-to: ("l", "c"))

  // making a cetz path snap to cetz objects
  let path = line((1,0), (1,2), (3,2), (3,0))
  edge(path, "<=", snap-to: ("l", "c"))
})