Working with Obsidian and Excalidraw for Animation and PDF Export
1
My motivation stemmed from creating a series of frames illustrating the implementation of window functions in PostgreSQL using Excalidraw within Obsidian. When played sequentially, these frames create an animation effect.
The Excalidraw plugin in Obsidian supports customizations. To achieve the animation playback, I modified the SlideShow plugin settings:
const TRANSITION_STEP_COUNT = 1;
const TRANSITION_DELAY = 0; //maximum time for transition between slides in milliseconds
const FRAME_SLEEP = 0; //milliseconds
This configuration enabled the desired frame-by-frame presentation within Obsidian.
2
For better sharing of my Excalidraw diagrams, I needed to export each frame as an image and compile them into a PDF document. I explored the obsidian-excalidraw-plugin capabilities.
The tutorial video: https://www.youtube.com/watch?v=hePJcObHIso&t=424s.
Ultimately, I was able to execute the following script in the Obsidian developer console to export all frames as SVG files:
exca = ExcalidrawAutomate
exca.setView('active')
eapi = exca.getExcalidrawAPI()
elements = exca.getViewElements()
frames = elements.filter(e => e.type == 'frame').sort((a, b) => a.name.localeCompare(b.name))
async function ssvg(index) {
activeView = exca.targetView;
vault = activeView.app.vault;
p = activeView.file.path;
p.indexOf('/') == -1 ? p = p : p = p.substring(p.lastIndexOf('/') + 1);
d = '/' + p.substring(0, p.indexOf(".")) + '_slides';
if (vault.getFolderByPath(d) == null)
vault.createFolder(d);
n = d + '/slide' + index + '.svg';
e = exca.getElementsInFrame(frames[index - 1], elements);
a = await activeView.svg({
elements: e,
appState: eapi.getAppState(),
files: exca.getExcalidrawAPI().getFiles(),
}, undefined, undefined, true);
o = (new XMLSerializer).serializeToString(a);
await vault.create(n, o);
}
for (var i = 1; i <= frames.length; i++) await ssvg(i);
With this, I could reference these images in Markdown files and export them to PDF.
3
To enhance the visual appeal of the generated PDF, I customized Obsidian's CSS snippets.
Relevant CSS snippet:
@media print {
hr {
page-break-after: always;
opacity: 0;
}
* {
font-size: 1.2em;
}
.HyperMD-list-line {
font-size: 1.4em;
}
/* Center images in exported PDF pages */
img {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
text-align: center;
margin: 0 auto;
}
}
I used this code block for displaying a title page:
<div style="font-size: 2em;text-align: center; display: flex; justify-content: center; align-items: center; height: 100vh">
internals of<br/> window function implementation
</div>
Final result: https://ldd.cool/pdf/windowagg.pdf