Text columns centered around an offset?

I want to create columns centered around an offset I choose. For example, I want to take this array: (("abc", 20%), ("def", 80)) and create a text row that looks like this:

1234567890 // for comparison
abc   def

how can I do this? I tried the following:

    let events = (("abc", 20%), ("def", 80))
    for (name, percent) in events {
          place(left, dx: percent, name)
    }

but that left-aligns the text starting at dx, instead of centering it around dx, which you can see in this demo here: Typst

I tried grid but it didn’t work in confusing ways, and stack doesn’t seem to support different offsets per column.

If there were a way to say let offset = percent - width(name)/2 that would be perfect, but I don’t think that width function exists.

The width function does exist, that sounds like measure. Something like this will tell you the width of [abc] in the current style - that’s why it depends on context:

context {
  let size = measure([abc])
  size  // size has fields height, width
}

Note that the result has to be used inside the same context block, or you can move the context scope really far out to encompass the whole function using this, in some cases.

If you need to measure something that line wraps or takes available page space into account, then you need to use layout in addition to measure.

1 Like

Hello, can you update your post?

What @bluss said.

#let pin-centered(dx: 0pt, dy: 0pt, body) = context {
  place(left, dx: dx - measure(body).width / 2, dy: dy, body)
}

#for i in range(11) {
  pin-centered(dx: 10% * i, repr(10% * i))
  place(dx: 10% * i, dy: 1em, line(angle: 90deg))
}

#let events = (("abc", 20%), ("def", 80%))
#for (name, percent) in events {
  pin-centered(dx: percent, dy: 4em, name)
}

image