#Subgroup labels for the SVG backend

14 messages · Page 1 of 1 (latest)

dense hill
#

I want to post-process the SVG output from Typst. Specifically, I want to annotate different parts in the Typst source document and be able to identify and extract these parts from the generated SVG. Is it already possible with the current supported features?

  • Ideally, I can make groups with unique labels. The grouping should then be preserved by the Typst compiler, and the unique labels for the groups should become e.g. "id" attributes in the SVG.
  • If preserving the grouping is not possible, the following would also work for me. If a group is inlined, the label for that group is transformed into e.g. "class" attributes and gets attached to the children elements.
    I checked the source code and saw that there are FrameItem::Meta elements which seems to provide the required information, but I got lost when tracing where these Metas are generated and transformed (because apparently the group structure is flattened and the Metas get duplicated in the final Frame).
frigid island
#

There is no builtin way to doing that. but if you are luckily enough, you can instrument it by special elements manually for post processing

#

At leat in a cetz canvas, it works.

dense hill
#

Thanks, but if I am not mistaken, the linked code performs the same transformation to every element matching a certain structure. What I hope to achieve is different: (1) start with a document with several groups of elements, (2) use Typst to generate an SVG image, (3) identify in the SVG which elements belong to which group. The goal is to separate the SVG document into several “sub-images” (or in other words, rearrange the SVG into several <g> elements), each of which corresponds to a group in the original Typst document.

frigid island
#

I think preprocess code prepares the (3) and postprocess code does the (rearrangement).

/// Create a group element for the tag
const g = document.createElement('g');
g.setAttribute('id', `cetz-app-${tag}`);
g.setAttribute('class', 'typst-cetz-elem');
g.append(...elements!);
elem.appendChild(g);
#

anyway, if you don't want to hack into typst internals, the answer is you cannot attach id or class to a group of typst elements.

dense hill
#

Ah, I did not express myself clear enough. Of course I have no problem with the fact that I need to do some pre- and post-processing. The problem was how to do it.
Let’s say for example I have $sin x + cos y + tan z$ as the example document, and I want to extract the three terms and the two plus signs as 5 separate groups. How do I know which paths correspond to which elements in the input? This is why I need some way to (1) attach labels to the subgroups in the input and (2) query the labels for each element in the output SVG. In the example, I would assign the numbers 1 through 5 to the 5 groups in the input (by preprocessing the Typst source), and collect the paths from each group. The question was about how I can assign these numbers and how I can query about them. And to be clear, I accept that I might need to wrap the Typst compiler and mess with the IR, but I hope I can do it in a way that does not involve modifying Typst itself. (For example, I’m okay with depending on the typst crates and writing a custom backend, but I don’t think modifying those crates is a good idea.)

#

Comparing to the existing features I know, it is similar to typst query, but on the output SVG instead of on the input source. This requires that some information persists through the whole compilation process, and I have access to that information both in the input Typst source file and in the final SVG.

frigid island
# dense hill Ah, I did not express myself clear enough. Of course I have no problem with the ...

My solution was just placing some special elements in a typst document and then iterating a svg tree and didn't modify typst at all. I translate my preprocess code to typst here:

let alloc-fill-by(loc, id) = {
  let a = fill-allocator.at(loc);
  ...
}
let svg-group(content, id: none) = locate(loc => {
  let identifiable-element = line(stroke: magic-stroke, fill: alloc-fill-by(loc, id))
  identifiable-element
  box(content)
  identifiable-element
})

With a magic-stroke, the postprocesor can find lower bound and upper bound position of a tagging element.
For your example, I think it is possible to attach "id" or "class" to the entire equation:

svg-group(id: "the-equation", {
  $sin x + cos y + tan z$
})

But it is quite hard to attach id to each math component, "sin x", "+", "cos y", and so on.

#

anyway, if you don't want to hack into typst internals, the answer is you cannot attach id or class to a group of typst elements.
You may need to propose some new meta primitives for typst to make it not so hacky, I think you may open an issue for this.

dusky otter
#

I think adding primitives for more fine-grained export control is planned but nothing concrete yet about how that would look

dense hill
#

I agree that adding new primitives is probably the proper way, but I feared that the use case might be too specific and it might not justify its own primitive. I think I’ll open an issue about this anyway, thanks!