cetz-package / cetz

CeTZ: ein Typst Zeichenpaket - A library for drawing stuff with Typst.
https://cetz-package.github.io
GNU Lesser General Public License v3.0
819 stars 35 forks source link

[Feature Request] Content-Relative Anchors #683

Closed timfi closed 6 days ago

timfi commented 1 month ago

Cetz currently doesn't support anchors whose position is relative to the properties of a nodes content—see base*, mid*, and text in the image below.

grafik (Credits to Packt for the image.)

After a short, productive discussion with @fenjalien (see #680), it turns out that:

No we currently don't [support] as it would require inspecting the provided content and measuring it. This is difficult as theres no official documentation for how content values are supposed to act and could change with any release. Once Typst provides more ways to control content it would be something we'll be looking into. — Originally commented by fenjalien in the discussion mentioned above.

johannes-wolf commented 1 month ago

I think we can create those anchors for content(..., frame: "rect|circle") content, because we can access the Typst content bounds.

timfi commented 1 month ago

I think we can create those anchors for content(..., frame: "rect|circle") content, because we can access the Typst content bounds.

Can one access them in the current version using the snippet you provided? And if so, what are the called?

johannes-wolf commented 1 month ago

No, we do not create them yet. How are you using content(...)? Are you using either padding: or frame:?

timfi commented 1 month ago

As it stands I'm using padding.

johannes-wolf commented 1 month ago

So all you want is "unpadded" anchors of the contents bounding box (more or less)?

timfi commented 1 month ago

Roughly, the most important feature to me is that the anchors are on the same height as the baseline of the content. This makes drawing things such that text lines up across multiple parts much easier. I'm not sure if that is exactly what you meant just now.

johannes-wolf commented 1 month ago

Not exactly, as Typst does not give access to the baseline. So no, this cannot be implemented right now.

timfi commented 1 month ago

Ok, I'm looking forward to whenever the folks over at Typst get around to implementing external access to such properties.

johannes-wolf commented 1 month ago

Wait… it should work. If you place two contents at (0,0), the baselines line up.

timfi commented 1 month ago

Without setting the anchors?

timfi commented 1 month ago

Or do the horizontal anchors naturally fall along the baseline of included text?

johannes-wolf commented 1 month ago

Yes, but only if padding is 0, I guess.

johannes-wolf commented 1 month ago

So what cetz needs to do, is to expose the bounding box anchors of the content without the padding applied.

timfi commented 1 month ago

Seems so. As long as the natural aligning of the baseline to the east and west anchor is something one can rely on.

johannes-wolf commented 1 month ago

No, east and west are centered. Sorry I missunderstood you. Here https://github.com/cetz-package/cetz/blob/b334fef19c0f27213c4f2eff962dd55334b831e3/src/draw/shapes.typ#L805 the anchors of the contents bbox get computed, which needs to be done twice; a second time without the padding.

timfi commented 1 month ago

Ah, I see. I guess this means waiting for Typst to properly expose these measurements/properties?

johannes-wolf commented 1 month ago

But you can get what you want with a workaround, I guess:

#import "@preview/cetz:0.2.2"
#set page(width: auto, height: auto)

#let content2(..args, anchor: none, name: none, padding: 0) = {
  cetz.draw.group(name: name, anchor: anchor, {
    cetz.draw.group(name: "tmp-group", padding: padding, {
      cetz.draw.content(..args, name: "content")
    })

    cetz.draw.rect("tmp-group.south-west", "tmp-group.north-east")

    cetz.draw.anchor("baseline-west", ("tmp-group.content.south-west", "-|", "tmp-group.west"))
    cetz.draw.anchor("baseline-east", ("tmp-group.content.south-east", "-|", "tmp-group.east"))
  })
}
#cetz.canvas({
  import cetz.draw: *

  content2((0, 10), [Alle Autos!], anchor: "south", padding: 1, name: "a")
  content2("a.baseline-east", [geile Autos, yeah! \ geniaiaeaeiaenein],
    anchor: "baseline-west")
})

Gives: grafik

So you can implement this feature via cetz itself :)

timfi commented 1 month ago

Wow! I'll need to give that a try a soon as I'm back in front of my machine.

timfi commented 4 weeks ago

@johannes-wolf Your workaround works nicely, thank you very much! But I believe it works since—and forgive me if I don't have the proper Typst terminology down—the bottom-edge of text objects is set to "baseline" by default, i.e., doesn't include descenders. Your example shows this nicely with the g poking out at the bottom of the second node.


As an aside, I'm bewilder by the fact that Typst doesn't automatically choose the smallest possible settings for bottom-edge and top-edge, but rather defaults to "baseline" and "cap-height", respectively. For me at least, this makes drawing tight boxes around arbitrary text unintuitive since one always needs to tweak the extents of the boxes based on the content. There may well be good reasons for this that I am unaware of; for example, I assume that layouting free form text is simplified a bit by this, since the baselines will just line up once all the text objects are vertically aligned along their bottom edge.

timfi commented 4 weeks ago

Though not particularly relevant to this issue if found a resolution to the aside in my previous comment. Typst also supports "bounds" for both top-edge and bottom-edge, which sets the limits—as the docs put it—to "the top/bottom edge of the glyph's bounding box".

johannes-wolf commented 4 weeks ago

@timfi Yes, I think Typsts measure should return multiple heights, one for the baseline and one for a tight bounding box that contains descenders. @laurmaedje, would that be possible? Should I create an issue?

laurmaedje commented 4 weeks ago

Would it be possible to instead measure twice with different settings for text edge?

johannes-wolf commented 4 weeks ago

Would it be possible to instead measure twice with different settings for text edge?

That should work, yes.

johannes-wolf commented 4 weeks ago

PR is ready.