Jollywatt / typst-fletcher

Typst package for drawing diagrams with arrows, built on top of CeTZ.
MIT License
411 stars 8 forks source link

Add support for edges connecting edges #16

Open btmxh opened 8 months ago

btmxh commented 8 months ago

In tikzcd, arrows' from and to could be a name of another arrow, which allows for arrows between arrows. This is somewhat supported in typst-fletcher, but in a kind of hacky way, as the user still need to figure the exact coordinates of the edge from and to.

Here is an example in the manual that involves a magic number h:

#fletcher.diagram(spacing: 2cm, {
let (A, B) = ((0,0), (1,0))
node(A, $cal(A)$)
node(B, $cal(B)$)
edge(A, B, $F$, "->", bend: +35deg)
edge(A, B, $G$, "->", bend: -35deg)
let h = 0.2
edge((.5,-h), (.5,+h), $alpha$, "=>")
})

I'm currently adding typst support for quiver, and of course there is always the option of calculating the coordinates in JS, but I think having typst-fletcher supporting edges connecting edges would be a better way to solve this problem.

Jollywatt commented 8 months ago

I do like this idea. The existing functionality to automatically snap to node outlines could easily be extended to edges, too. The main problem is coming up with the best interface for doing this sort of snapping.

I used to dislike the idea of giving nodes “names”, à la tikz (see #8), but increasingly I think it might be a good idea. If edges can also be named, then you could do something like

#fletcher.diagram(spacing: 2cm, {
  let (A, B) = ((0,0), (1,0))
  node(A, $cal(A)$)
  node(B, $cal(B)$)
  edge(A, B, $F$, "->", bend: +35deg, name: "F")
  edge(A, B, $G$, "->", bend: -35deg, name: "G")
  edge(vertices: ("F", "G"), $alpha$, "=>")
})

However, I still think it's important to have the freedom offered by coordinates, so you can ‘nudge’ edges slightly (e.g., an edge connecting to (0.1, 0) will still snap to a node at (0, 0), just slightly off center). In that case, you could have something like edge((.5, -1), (.5, +1), $alpha$, "=>", snap-to: ("F", "G")). Arguably, this still has a “magic” y-coordinate which needs to be large enough to overshoot the curved edges so that snapping occurs.

Interested in your thoughts on the best interface for this.

P.S., I haven’t had the time to catch up with issues recently - such is the way of FOSS!

btmxh commented 8 months ago

Personally, I think letting node() and edge() return a handle to the node/edge as a variable is a good alternative for having names, i.e.

#fletcher.diagram(spacing: 2cm, {
  let A = node((0,0), $cal(A)$)
  let B = node((1,0), $cal(B)$)
  let F = edge(A, B, $F$, "->", bend: +35deg)
  let G = edge(A, B, $G$, "->", bend: -35deg)
  edge(vertices: (F, G), $alpha$, "=>")
})

For nudging, maybe we could add some offset arguments or directly translating the handle by some amount. The translated handle can be represented as a pair containing the node name and the nudging offset.