I’ve created a long document containing dozens of figures using CetZ. I’d like to programmatically export each CetZ figure as a separate SVG file so I can use them individually in a different context.
What’s the best way to achieve this?
I’ve created a long document containing dozens of figures using CetZ. I’d like to programmatically export each CetZ figure as a separate SVG file so I can use them individually in a different context.
What’s the best way to achieve this?
While this is not an automated way to achieve it, what I have done is creating a new empty project in the web app with the lines of code below, setting document size to auto
, copying the cetz figure code and exporting the document as svg, which I then uploaded to my actual project.
#import "@preview/cetz:0.3.4"
#set page(margin: 5mm, fill: white, width: auto, height: auto)
// Your cetz figure here
But I would love to see a more automated workflow for this. Or ideally this would not be required because making no performance difference to just leaving whatever number of cetz figures in the document. My experience is that having a few dozens of objects in cetz, especially with relative positioning, makes the whole document super slow even when not actively working on the figures (which in my understanding shouldn’t be the case wrt caching etc…)
FYI, the name is CeTZ.
How exactly are figures inserted in the source file? If plainly from the markup mode, then it would be something like this:
#import "@preview/cetz:0.3.4"
#set page(width: auto, height: auto, margin: 0.5pt)
#set pagebreak(weak: true)
#cetz.canvas(cetz.draw.circle(()))
#pagebreak()
#cetz.canvas(cetz.draw.circle(()))
#pagebreak()
See Add support for inside/center/outside strokes (change stroke bounding box) · Issue #5741 · typst/typst · GitHub about page margins.
Or maybe this:
#import "@preview/cetz:0.3.4"
#set page(width: auto, height: auto, margin: 0.5pt)
#let canvas(..args) = cetz.canvas(..args) + pagebreak(weak: true)
#canvas(cetz.draw.circle(()))
#canvas(cetz.draw.circle(()))
Then obviously just compile into SVG format and you will have one figure per page, i.e., one figure per SVG file.
The figures are embedded within a long report, alongside text, tables, equations, and other elements. I would prefer to keep the original source code unchanged. However, the source code could be included in another file where the extraction of the figures can take place.
You don’t say how the canvas
is called, so you might have to change the source after all, because you can’t identify/tag figures without doing anything.
#import "@preview/cetz:0.3.4"
#let canvas(..args) = {
let body = cetz.canvas(..args)
[#body#metadata(body)<something>]
}
#lorem(50)
#canvas(cetz.draw.circle(()))
#lorem(50)
#canvas(cetz.draw.circle(()))
#lorem(50)
#set page(width: auto, height: auto, margin: 0.5pt)
#show: doc => context {
place(hide(doc))
query(<something>)
.map(x => x.value)
.intersperse(pagebreak(weak: true))
.join()
}
#include "source.typ"
Wow, that is interesting!
The way I call is
#figure(caption: [Bending stress], placement:none,
cetz.canvas({
import cetz.draw: *
// stuff
}),
)<fig:bending-stress>
Maybe a show rule could modify the cetz.canvas
behavior.
No, the canvas
function uses context
right away, so there is absolutely no way to get that without help from the inside of the library.
Since you are using figure
, this means it can be used instead, but only if all figures are from CeTZ. Otherwise, you can check for whether the it.body.func() == (context {}).func()
and hopefully any other figures don’t use context
.
#import "@preview/cetz:0.3.4"
#show figure: it => [#it#metadata(it.body)<something>]
#lorem(50)
#figure(caption: [Bending stress], cetz.canvas({
import cetz.draw: *
circle(())
})) <fig:bending-stress>
#lorem(50)
#figure(cetz.canvas({
import cetz.draw: *
circle(())
}))
#lorem(50)
Excellent! Thanks @Andrew. I learned a lot!